hermes-io 2.2.5 → 2.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/package.json +1 -1
- package/examples/sneaker-store/. quokka +0 -25
- package/examples/sneaker-store/.editorconfig +0 -32
- package/examples/sneaker-store/.eslintrc.js +0 -24
- package/examples/sneaker-store/LICENSE +0 -21
- package/examples/sneaker-store/README.md +0 -1
- package/examples/sneaker-store/config-overrides.js +0 -35
- package/examples/sneaker-store/jsconfig.json +0 -20
- package/examples/sneaker-store/package-lock.json +0 -39849
- package/examples/sneaker-store/package.json +0 -48
- package/examples/sneaker-store/public/assets/images/addidas.webp +0 -0
- package/examples/sneaker-store/public/assets/images/jordan_3.webp +0 -0
- package/examples/sneaker-store/public/favicon.ico +0 -0
- package/examples/sneaker-store/public/index.html +0 -46
- package/examples/sneaker-store/public/logo192.png +0 -0
- package/examples/sneaker-store/public/logo512.png +0 -0
- package/examples/sneaker-store/public/manifest.json +0 -25
- package/examples/sneaker-store/public/reset.css +0 -48
- package/examples/sneaker-store/public/robots.txt +0 -3
- package/examples/sneaker-store/src/core/App.js +0 -72
- package/examples/sneaker-store/src/core/actions/Theme.js +0 -5
- package/examples/sneaker-store/src/core/actions/index.js +0 -3
- package/examples/sneaker-store/src/core/constants.js +0 -4
- package/examples/sneaker-store/src/core/contexts.js +0 -4
- package/examples/sneaker-store/src/core/factory/Actions.js +0 -8
- package/examples/sneaker-store/src/core/factory/Observer.js +0 -3
- package/examples/sneaker-store/src/core/observers/products.js +0 -6
- package/examples/sneaker-store/src/core/theme.js +0 -26
- package/examples/sneaker-store/src/core/views/components/Products/Products.js +0 -55
- package/examples/sneaker-store/src/core/views/components/Products/Styles.js +0 -112
- package/examples/sneaker-store/src/core/views/components/ShoppingCar/ShoppingCar.js +0 -56
- package/examples/sneaker-store/src/core/views/components/ShoppingCar/Styles.js +0 -59
- package/examples/sneaker-store/src/core/views/hooks/index.js +0 -0
- package/examples/sneaker-store/src/index.js +0 -10
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "atomic-client",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"dependencies": {
|
|
6
|
-
"@testing-library/jest-dom": "^5.16.5",
|
|
7
|
-
"@testing-library/react": "^13.4.0",
|
|
8
|
-
"@testing-library/user-event": "^13.5.0",
|
|
9
|
-
"react": "18.2.0",
|
|
10
|
-
"react-dom": "18.2.0",
|
|
11
|
-
"styled-components": "^5.3.6"
|
|
12
|
-
},
|
|
13
|
-
"scripts": {
|
|
14
|
-
"start": "PORT=8000 react-app-rewired start",
|
|
15
|
-
"deploy": "react-app-rewired build && now",
|
|
16
|
-
"build": "react-app-rewired build",
|
|
17
|
-
"test": "react-app-rewired test",
|
|
18
|
-
"eject": "react-app-rewired eject",
|
|
19
|
-
"build-storybook": "build-storybook -s public"
|
|
20
|
-
},
|
|
21
|
-
"eslintConfig": {
|
|
22
|
-
"extends": [
|
|
23
|
-
"react-app",
|
|
24
|
-
"react-app/jest"
|
|
25
|
-
]
|
|
26
|
-
},
|
|
27
|
-
"browserslist": {
|
|
28
|
-
"production": [
|
|
29
|
-
">0.2%",
|
|
30
|
-
"not dead",
|
|
31
|
-
"not op_mini all"
|
|
32
|
-
],
|
|
33
|
-
"development": [
|
|
34
|
-
"last 1 chrome version",
|
|
35
|
-
"last 1 firefox version",
|
|
36
|
-
"last 1 safari version"
|
|
37
|
-
]
|
|
38
|
-
},
|
|
39
|
-
"devDependencies": {
|
|
40
|
-
"@babel/register": "^7.18.9",
|
|
41
|
-
"@emotion/react": "^11.10.5",
|
|
42
|
-
"@emotion/styled": "^11.10.5",
|
|
43
|
-
"esbuild-loader": "^2.20.0",
|
|
44
|
-
"eslint": "^8.29.0",
|
|
45
|
-
"eslint-plugin-react": "^7.31.11",
|
|
46
|
-
"react-app-rewired": "^2.2.1"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
-
<meta name="theme-color" content="#000000" />
|
|
8
|
-
<meta
|
|
9
|
-
name="description"
|
|
10
|
-
content="Web site created using create-react-app"
|
|
11
|
-
/>
|
|
12
|
-
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
|
13
|
-
<!--
|
|
14
|
-
manifest.json provides metadata used when your web app is installed on a
|
|
15
|
-
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
|
16
|
-
-->
|
|
17
|
-
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
|
18
|
-
<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@700&family=Raleway:wght@100&display=swap" rel="stylesheet">
|
|
19
|
-
<style> @import url('https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@700&family=Raleway:wght@100&display=swap'); </style>
|
|
20
|
-
<link rel="stylesheet" href="./reset.css">
|
|
21
|
-
<!--
|
|
22
|
-
Notice the use of %PUBLIC_URL% in the tags above.
|
|
23
|
-
It will be replaced with the URL of the `public` folder during the build.
|
|
24
|
-
Only files inside the `public` folder can be referenced from the HTML.
|
|
25
|
-
|
|
26
|
-
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
|
27
|
-
work correctly both with client-side routing and a non-root public URL.
|
|
28
|
-
Learn how to configure a non-root public URL by running `npm run build`.
|
|
29
|
-
-->
|
|
30
|
-
<title>Sneaker store</title>
|
|
31
|
-
</head>
|
|
32
|
-
<body>
|
|
33
|
-
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
34
|
-
<div id="root"></div>
|
|
35
|
-
<!--
|
|
36
|
-
This HTML file is a template.
|
|
37
|
-
If you open it directly in the browser, you will see an empty page.
|
|
38
|
-
|
|
39
|
-
You can add webfonts, meta tags, or analytics to this file.
|
|
40
|
-
The build step will place the bundled scripts into the <body> tag.
|
|
41
|
-
|
|
42
|
-
To begin the development, run `npm start` or `yarn start`.
|
|
43
|
-
To create a production bundle, use `npm run build` or `yarn build`.
|
|
44
|
-
-->
|
|
45
|
-
</body>
|
|
46
|
-
</html>
|
|
Binary file
|
|
Binary file
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"short_name": "React App",
|
|
3
|
-
"name": "Create React App Sample",
|
|
4
|
-
"icons": [
|
|
5
|
-
{
|
|
6
|
-
"src": "favicon.ico",
|
|
7
|
-
"sizes": "64x64 32x32 24x24 16x16",
|
|
8
|
-
"type": "image/x-icon"
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"src": "logo192.png",
|
|
12
|
-
"type": "image/png",
|
|
13
|
-
"sizes": "192x192"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"src": "logo512.png",
|
|
17
|
-
"type": "image/png",
|
|
18
|
-
"sizes": "512x512"
|
|
19
|
-
}
|
|
20
|
-
],
|
|
21
|
-
"start_url": ".",
|
|
22
|
-
"display": "standalone",
|
|
23
|
-
"theme_color": "#000000",
|
|
24
|
-
"background_color": "#ffffff"
|
|
25
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/* http://meyerweb.com/eric/tools/css/reset/
|
|
2
|
-
v2.0 | 20110126
|
|
3
|
-
License: none (public domain)
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
html, body, div, span, applet, object, iframe,
|
|
7
|
-
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
|
8
|
-
a, abbr, acronym, address, big, cite, code,
|
|
9
|
-
del, dfn, em, img, ins, kbd, q, s, samp,
|
|
10
|
-
small, strike, strong, sub, sup, tt, var,
|
|
11
|
-
b, u, i, center,
|
|
12
|
-
dl, dt, dd, ol, ul, li,
|
|
13
|
-
fieldset, form, label, legend,
|
|
14
|
-
table, caption, tbody, tfoot, thead, tr, th, td,
|
|
15
|
-
article, aside, canvas, details, embed,
|
|
16
|
-
figure, figcaption, footer, header, hgroup,
|
|
17
|
-
menu, nav, output, ruby, section, summary,
|
|
18
|
-
time, mark, audio, video {
|
|
19
|
-
margin: 0;
|
|
20
|
-
padding: 0;
|
|
21
|
-
border: 0;
|
|
22
|
-
font-size: 100%;
|
|
23
|
-
font: inherit;
|
|
24
|
-
vertical-align: baseline;
|
|
25
|
-
}
|
|
26
|
-
/* HTML5 display-role reset for older browsers */
|
|
27
|
-
article, aside, details, figcaption, figure,
|
|
28
|
-
footer, header, hgroup, menu, nav, section {
|
|
29
|
-
display: block;
|
|
30
|
-
}
|
|
31
|
-
body {
|
|
32
|
-
line-height: 1;
|
|
33
|
-
}
|
|
34
|
-
ol, ul {
|
|
35
|
-
list-style: none;
|
|
36
|
-
}
|
|
37
|
-
blockquote, q {
|
|
38
|
-
quotes: none;
|
|
39
|
-
}
|
|
40
|
-
blockquote:before, blockquote:after,
|
|
41
|
-
q:before, q:after {
|
|
42
|
-
content: '';
|
|
43
|
-
content: none;
|
|
44
|
-
}
|
|
45
|
-
table {
|
|
46
|
-
border-collapse: collapse;
|
|
47
|
-
border-spacing: 0;
|
|
48
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import { ThemeProvider } from "styled-components";
|
|
3
|
-
import Products from "@components/Products/Products"
|
|
4
|
-
import ShoppingCar from "@components/ShoppingCar/ShoppingCar";
|
|
5
|
-
import { useObserver } from "hermes-io";
|
|
6
|
-
import ProductsObservers from '@observers/products';
|
|
7
|
-
import theme from '@theme';
|
|
8
|
-
import * as contexts from '@contexts';
|
|
9
|
-
|
|
10
|
-
const sneakerList = [
|
|
11
|
-
{
|
|
12
|
-
id: '1',
|
|
13
|
-
name: 'Jordan',
|
|
14
|
-
image: '/assets/images/jordan_3.webp',
|
|
15
|
-
description: 'Air Jordan 3 Retro OG',
|
|
16
|
-
price: '250'
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
id: '2',
|
|
20
|
-
image: '/assets/images/addidas.webp',
|
|
21
|
-
description: 'Bad Bunny Forum Buckle Low sneakers',
|
|
22
|
-
name: 'Adidas Forum',
|
|
23
|
-
price: '200'
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
id: '3',
|
|
27
|
-
image: '/assets/images/addidas.webp',
|
|
28
|
-
description: 'Bad Bunny Forum Buckle Low sneakers',
|
|
29
|
-
name: 'Adidas Forum',
|
|
30
|
-
price: '200'
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
const productsStore = new Map();
|
|
35
|
-
productsStore.set('collection', sneakerList);
|
|
36
|
-
|
|
37
|
-
const filterSelectes = (collection) => collection.filter((item) => item.selected);
|
|
38
|
-
|
|
39
|
-
function App() {
|
|
40
|
-
const [products, setProducts] = useState(productsStore.get('collection'));
|
|
41
|
-
|
|
42
|
-
const handleRemoveProduct = ({ value: product = {} }) => {
|
|
43
|
-
product.selected = false;
|
|
44
|
-
setProducts([...productsStore.get('collection')]);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const handleAddProduct = ({ value: product = {} }) => {
|
|
48
|
-
product.selected = true;
|
|
49
|
-
setProducts([...productsStore.get('collection')]);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
useObserver({
|
|
53
|
-
observer: ProductsObservers.add,
|
|
54
|
-
listener: handleAddProduct,
|
|
55
|
-
contexts: [contexts.products],
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
useObserver({
|
|
59
|
-
observer: ProductsObservers.remove,
|
|
60
|
-
listener: handleRemoveProduct,
|
|
61
|
-
contexts: [contexts.shoppingCar, contexts.products],
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<ThemeProvider theme={theme}>
|
|
66
|
-
<ShoppingCar data={filterSelectes(products)} />
|
|
67
|
-
<Products variant='grid' data={products} />
|
|
68
|
-
</ThemeProvider>
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export default App;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const theme = {
|
|
2
|
-
colors: {
|
|
3
|
-
primary: "#1A090D",
|
|
4
|
-
secondary: "#F8F8F8",
|
|
5
|
-
third: "#011638",
|
|
6
|
-
fourth: "#fafafa",
|
|
7
|
-
fifth: "#E3170A",
|
|
8
|
-
contrast: {
|
|
9
|
-
primary: "#fff",
|
|
10
|
-
secondary: "#1A090D",
|
|
11
|
-
third: "#fff",
|
|
12
|
-
fifth: "#fff",
|
|
13
|
-
fourth: "#000",
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
typography: {
|
|
17
|
-
primary: {
|
|
18
|
-
fontFamily: "Josefin Sans",
|
|
19
|
-
},
|
|
20
|
-
secondary: {
|
|
21
|
-
fontFamily: "Raleway, sans-serif",
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export default theme;
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
Image,
|
|
4
|
-
List,
|
|
5
|
-
Card,
|
|
6
|
-
Content,
|
|
7
|
-
Title,
|
|
8
|
-
Description,
|
|
9
|
-
Price,
|
|
10
|
-
Button,
|
|
11
|
-
} from "./Styles";
|
|
12
|
-
import ProductsObserver from "@observers/products";
|
|
13
|
-
import * as contexts from "@contexts";
|
|
14
|
-
|
|
15
|
-
const Products = (props = {}) => {
|
|
16
|
-
const { data = [] } = props;
|
|
17
|
-
|
|
18
|
-
const handleAddProduct = (product = {}) => {
|
|
19
|
-
ProductsObserver.add.notify({ value: product, context: contexts.products });
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const handleRemoveProduct = (product = {}) => {
|
|
23
|
-
ProductsObserver.remove.notify({
|
|
24
|
-
value: product,
|
|
25
|
-
context: contexts.products,
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<List variant={props.variant}>
|
|
31
|
-
{data.map((product = {}) => (
|
|
32
|
-
<Card key={product.id}>
|
|
33
|
-
<Image title={product.name} src={product.image} />
|
|
34
|
-
<Content active={props.active}>
|
|
35
|
-
<Title title={product.name}>{product.name}</Title>
|
|
36
|
-
<Description title={product.description}>{product.description}</Description>
|
|
37
|
-
<Price title={product.price}>${product.price}</Price>
|
|
38
|
-
<Button
|
|
39
|
-
title={product.selected ? "Remove from car" : "Add to car"}
|
|
40
|
-
onClick={() =>
|
|
41
|
-
product.selected
|
|
42
|
-
? handleRemoveProduct(product)
|
|
43
|
-
: handleAddProduct(product)
|
|
44
|
-
}
|
|
45
|
-
>
|
|
46
|
-
{product.selected ? "Remove from" : "Add to"} car
|
|
47
|
-
</Button>
|
|
48
|
-
</Content>
|
|
49
|
-
</Card>
|
|
50
|
-
))}
|
|
51
|
-
</List>
|
|
52
|
-
);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export default Products;
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import styled from "styled-components";
|
|
2
|
-
|
|
3
|
-
export const List = styled.ul`
|
|
4
|
-
display: ${(props = {}) => props.variant === 'grid' ? 'grid' : 'flex'};
|
|
5
|
-
${(props = {}) => props.variant === 'grid' && 'grid-template-columns: repeat(2, 1fr)'};
|
|
6
|
-
flex-direction: column;
|
|
7
|
-
flex-wrap: nowrap;
|
|
8
|
-
list-style: none;
|
|
9
|
-
padding: 0;
|
|
10
|
-
justify-content: center;
|
|
11
|
-
width: ${(props = {}) => props.variant === 'grid' ? '95%' : '800px' };
|
|
12
|
-
padding: ${(props = {}) => props.variant === 'grid' ? '30px' : '0px' };
|
|
13
|
-
margin: 80px auto;
|
|
14
|
-
`;
|
|
15
|
-
|
|
16
|
-
export const Card = styled.li`
|
|
17
|
-
align-items: center;
|
|
18
|
-
margin: 1rem;
|
|
19
|
-
display: grid;
|
|
20
|
-
grid-template-columns: 0.7fr 1fr;
|
|
21
|
-
height: 250px;
|
|
22
|
-
`;
|
|
23
|
-
|
|
24
|
-
export const Content = styled.div`
|
|
25
|
-
display: flex;
|
|
26
|
-
background: ${({theme = {}, active }) => active ? theme.colors.contrast.secondary : theme.colors.secondary};
|
|
27
|
-
flex-direction: column;
|
|
28
|
-
line-height: 1.3;
|
|
29
|
-
padding-top: 25px;
|
|
30
|
-
padding-left: 25px;
|
|
31
|
-
padding-bottom: 25px;
|
|
32
|
-
transition: all 0.25s ease-in;
|
|
33
|
-
& p, h2, h3 {
|
|
34
|
-
color: ${({ theme = {}, active }) => active ? theme.colors.contrast.primary : theme.colors.primary};
|
|
35
|
-
}
|
|
36
|
-
&:hover {
|
|
37
|
-
background: ${({theme = {}}) => theme.colors.contrast.secondary};
|
|
38
|
-
padding-top: 30px;
|
|
39
|
-
padding-bottom: 30px;
|
|
40
|
-
}
|
|
41
|
-
&:hover h2 {
|
|
42
|
-
color: ${({theme = {}}) => theme.colors.contrast.primary};
|
|
43
|
-
}
|
|
44
|
-
&:hover h3 {
|
|
45
|
-
color: ${({theme = {}}) => theme.colors.contrast.primary};
|
|
46
|
-
}
|
|
47
|
-
&:hover p {
|
|
48
|
-
color: ${({theme = {}}) => theme.colors.contrast.primary};
|
|
49
|
-
}
|
|
50
|
-
`;
|
|
51
|
-
|
|
52
|
-
export const Title = styled.h2`
|
|
53
|
-
color: ${({ theme = {} }) => theme.colors.primary}};
|
|
54
|
-
text-transform: capitalize;
|
|
55
|
-
font-size: 2.5rem;
|
|
56
|
-
font-family: ${({ theme = {} }) => theme.typography.primary.fontFamily};
|
|
57
|
-
font-weight: bold;
|
|
58
|
-
margin: 0;
|
|
59
|
-
`;
|
|
60
|
-
|
|
61
|
-
export const Image = styled.div`
|
|
62
|
-
border: 2px solid ${({ theme = {} }) => theme.colors.primary}};
|
|
63
|
-
background-image: url(${(props) => props.src});
|
|
64
|
-
background-color: white;
|
|
65
|
-
background-size: 78%;
|
|
66
|
-
background-repeat: no-repeat;
|
|
67
|
-
background-position: center bottom;
|
|
68
|
-
height: 100%;
|
|
69
|
-
transition: all 0.3s;
|
|
70
|
-
&:hover {
|
|
71
|
-
border: 4px solid ${({ theme = {} }) => theme.colors.primary};
|
|
72
|
-
background-size: 90%;
|
|
73
|
-
}
|
|
74
|
-
`;
|
|
75
|
-
|
|
76
|
-
export const Description = styled.p`
|
|
77
|
-
font-family: ${({ theme = {} }) => theme.typography.secondary.fontFamily};
|
|
78
|
-
color: ${({ theme = {} }) => theme.colors.third};
|
|
79
|
-
font-size: 1rem;
|
|
80
|
-
font-weight: 100;
|
|
81
|
-
text-transform: capitalize;
|
|
82
|
-
font-style: italic;
|
|
83
|
-
`;
|
|
84
|
-
|
|
85
|
-
export const Price = styled.h3`
|
|
86
|
-
color: ${({ theme = {} }) => theme.colors.third};
|
|
87
|
-
font-family: ${({ theme = {} }) => theme.typography.primary.fontFamily};
|
|
88
|
-
font-size: 15px;
|
|
89
|
-
font-weight: 100;
|
|
90
|
-
margin-top: 10px;
|
|
91
|
-
`;
|
|
92
|
-
|
|
93
|
-
export const Button = styled.button`
|
|
94
|
-
cursor: pointer;
|
|
95
|
-
font-size: 1rem;
|
|
96
|
-
font-weight: bold;
|
|
97
|
-
display: flex;
|
|
98
|
-
align-self: flex-end;
|
|
99
|
-
position: relative;
|
|
100
|
-
top: 10px;
|
|
101
|
-
right: 20px;
|
|
102
|
-
font-family: ${({ theme = {} }) => theme.typography.primary.fontFamily};
|
|
103
|
-
border: 2px solid ${({ theme = {} }) => theme.colors.fifth};
|
|
104
|
-
background: ${({ theme = {} }) => theme.colors.fifth};
|
|
105
|
-
color: ${({ theme = {} }) => theme.colors.contrast.primary};
|
|
106
|
-
padding: 10px;
|
|
107
|
-
transition: all 0.3s;
|
|
108
|
-
opacity: ${({ disabled }) => disabled ? 0.5 : 1};
|
|
109
|
-
&:hover {
|
|
110
|
-
padding: 15px;
|
|
111
|
-
}
|
|
112
|
-
`;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import React, { useState, useRef, useEffect } from "react";
|
|
2
|
-
import Products from "@components/Products/Products";
|
|
3
|
-
import { Anchor, Content, Header, Total, WrapperStyles } from "./Styles";
|
|
4
|
-
|
|
5
|
-
const calculateTotal = (data = []) =>
|
|
6
|
-
data.reduce((acc, { price = 0 }) => acc + Number(price), 0);
|
|
7
|
-
|
|
8
|
-
const Wrapper = (props) => {
|
|
9
|
-
const contentRef = useRef(null);
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
const { anchor = {} } = props;
|
|
12
|
-
const { left = 0 } = anchor;
|
|
13
|
-
const padding = -10;
|
|
14
|
-
const content = contentRef.current;
|
|
15
|
-
const { width } = content.getBoundingClientRect();
|
|
16
|
-
content.style.left = `${left - width - padding}px`;
|
|
17
|
-
}, []);
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<div style={{ ...WrapperStyles }} ref={contentRef}>
|
|
21
|
-
{props.children}
|
|
22
|
-
</div>
|
|
23
|
-
);
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const ShoppingCar = (props = {}) => {
|
|
27
|
-
const [showProducts, setShowProducts] = useState(false);
|
|
28
|
-
const anchorRef = useRef(null);
|
|
29
|
-
const { data = [] } = props;
|
|
30
|
-
const total = calculateTotal(data);
|
|
31
|
-
|
|
32
|
-
const handleDisplayCar = (e) => {
|
|
33
|
-
anchorRef.current = e.target.getBoundingClientRect();
|
|
34
|
-
setShowProducts(!showProducts);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
return (
|
|
38
|
-
<>
|
|
39
|
-
<Header>
|
|
40
|
-
<Anchor onClick={handleDisplayCar}>
|
|
41
|
-
🛒 {data.length ? data.length : null}
|
|
42
|
-
</Anchor>
|
|
43
|
-
</Header>
|
|
44
|
-
{showProducts && total > 0 ? (
|
|
45
|
-
<Wrapper total={total} anchor={anchorRef.current}>
|
|
46
|
-
<Content>
|
|
47
|
-
<Products active={true} data={data} />
|
|
48
|
-
<Total>Total: ${total}</Total>
|
|
49
|
-
</Content>
|
|
50
|
-
</Wrapper>
|
|
51
|
-
) : null}
|
|
52
|
-
</>
|
|
53
|
-
);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
export default ShoppingCar;
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import styled from "styled-components";
|
|
2
|
-
import theme from "@theme";
|
|
3
|
-
|
|
4
|
-
export const Anchor = styled.div`
|
|
5
|
-
align-self: center;
|
|
6
|
-
color: ${({ theme = {} }) => theme.colors.contrast.primary};
|
|
7
|
-
cursor: pointer;
|
|
8
|
-
display: inline;
|
|
9
|
-
padding: 20px;
|
|
10
|
-
text-align: center;
|
|
11
|
-
text-transform: uppercase;
|
|
12
|
-
font-size: 1.4rem;
|
|
13
|
-
font-family: ${({ theme = {} }) => theme.typography.primary.fontFamily};
|
|
14
|
-
width: 50px;
|
|
15
|
-
height: 20px;
|
|
16
|
-
margin-right: 50px;
|
|
17
|
-
transition: all 0.35s;
|
|
18
|
-
`;
|
|
19
|
-
|
|
20
|
-
export const Header = styled.header`
|
|
21
|
-
background: ${({ theme = {} }) => theme.colors.primary};
|
|
22
|
-
margin-bottom: 20px;
|
|
23
|
-
width: 100%;
|
|
24
|
-
height: 80px;
|
|
25
|
-
display: flex;
|
|
26
|
-
justify-content: flex-end;
|
|
27
|
-
z-index: 2;
|
|
28
|
-
`;
|
|
29
|
-
|
|
30
|
-
export const Content = styled.div`
|
|
31
|
-
background: ${({ theme = {} }) => theme.colors.primary};
|
|
32
|
-
ul {
|
|
33
|
-
margin: 0px;
|
|
34
|
-
}
|
|
35
|
-
`;
|
|
36
|
-
|
|
37
|
-
export const Total = styled.div`
|
|
38
|
-
border-top: 1px dashed ${({ theme = {} }) => theme.colors.contrast.primary};
|
|
39
|
-
color: ${({ theme = {} }) => theme.colors.contrast.primary};
|
|
40
|
-
font-family: ${({ theme = {} }) => theme.typography.primary.fontFamily};
|
|
41
|
-
font-size: 2rem;
|
|
42
|
-
padding: 20px;
|
|
43
|
-
padding-left: 0px;
|
|
44
|
-
width: 90%;
|
|
45
|
-
height: 2px;
|
|
46
|
-
margin: 20px auto;
|
|
47
|
-
`;
|
|
48
|
-
|
|
49
|
-
export const WrapperStyles = {
|
|
50
|
-
background: theme.colors.primary,
|
|
51
|
-
transform: "scale(0.7)",
|
|
52
|
-
top: "-10px",
|
|
53
|
-
overflowY: "auto",
|
|
54
|
-
position: "fixed",
|
|
55
|
-
padding: "30px",
|
|
56
|
-
transition: "all 0.35s",
|
|
57
|
-
width: "800px",
|
|
58
|
-
zIndex: "2",
|
|
59
|
-
};
|
|
File without changes
|