Skip to content

Commit 10e5997

Browse files
author
Vincenius
committed
add css generation for skewed separator
1 parent fb14d81 commit 10e5997

File tree

6 files changed

+183
-79
lines changed

6 files changed

+183
-79
lines changed

components/Generator/Controls.js

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
1-
import React from 'react'
1+
import React, { useState } from 'react'
22
import { Paper, Tabs, Tab, Slider, Checkbox } from '@material-ui/core'
3+
import { ExpandLess, ExpandMore, FileCopy } from '@material-ui/icons'
34
import * as S from './styled'
5+
import { generateHtmlCode, generateCssCode } from './codeGenerators'
46

57
const Controls = props => {
6-
const { setOptions, options } = props
8+
const { setOptions, options, active } = props
79
const [value, setValue] = React.useState(0)
10+
const [isVisible, setVisible] = React.useState(true)
11+
const [copiedCode, showCopied] = useState('')
12+
13+
const htmlCode = generateHtmlCode(active)
14+
const cssCode = generateCssCode({ active, options })
15+
16+
let htmlTextArea = React.createRef()
17+
let cssTextArea = React.createRef()
18+
19+
const copyToClipboard = (textArea, areaName) => {
20+
textArea.current.select()
21+
document.execCommand('copy')
22+
showCopied(areaName)
23+
24+
setTimeout( () => {
25+
showCopied('')
26+
}, 2000);
27+
}
828

929
const handleCheck = e => {
1030
setOptions({ ...options, [e.target.name]: e.target.checked });
@@ -30,7 +50,7 @@ const Controls = props => {
3050
<Tab label="HTML" />
3151
<Tab label="CSS" />
3252
</Tabs>
33-
<S.ControlContent>
53+
<S.ControlContent isVisible={isVisible}>
3454
{ value === 0 &&
3555
<div>
3656
{ options.reversed !== undefined &&
@@ -62,16 +82,33 @@ const Controls = props => {
6282
}
6383
{ value === 1 &&
6484
<div>
65-
THE HTML
85+
<FileCopy onClick={() => copyToClipboard(htmlTextArea, 'html')} />
86+
<S.Copied visible={copiedCode === 'html'}>copied</S.Copied>
87+
<S.CodeArea
88+
value={htmlCode}
89+
rowsMax={5}
90+
marginBottom={true}
91+
ref={htmlTextArea}
92+
/>
6693
</div>
6794
}
6895
{ value === 2 &&
6996
<div>
70-
THE CSS
97+
<FileCopy onClick={() => copyToClipboard(cssTextArea, 'css')} />
98+
<S.Copied visible={copiedCode === 'css'}>copied</S.Copied>
99+
<S.CodeArea
100+
value={cssCode}
101+
rowsMax={5}
102+
marginBottom={true}
103+
ref={cssTextArea}
104+
/>
71105
</div>
72106
}
73-
{ /* TODO hide (arrow up) button on mobile */ }
74107
</S.ControlContent>
108+
<S.ControlToggle onClick={() => setVisible(!isVisible)}>
109+
{ isVisible && <span><ExpandLess /> Hide</span>}
110+
{ !isVisible && <span><ExpandMore /> Show</span> }
111+
</S.ControlToggle>
75112
</S.Controls>
76113
)
77114
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { SEPARATORS } from './constants'
2+
import { darkGrey } from '../../ui/constants'
3+
4+
export const generateHtmlCode = active => [SEPARATORS.SKEWED, SEPARATORS.WAVE].includes(active)
5+
? `<section>
6+
<div class="${active}"></div>
7+
</section>`
8+
: `<section class="${active}"></section>`
9+
10+
export const generateCssCode = ({ active, options }) => {
11+
// TODO check what to generate
12+
return `.${active} {
13+
${generateSkewCss(options)}
14+
}`
15+
}
16+
17+
export const generateSkewCss = ({ angle, reversed }) =>
18+
`position: absolute;
19+
top: 0;
20+
bottom: 0;
21+
right: 0;
22+
left: 0;
23+
width: 100%;
24+
height: 100%;
25+
background: ${darkGrey};
26+
z-index: 0;
27+
${!reversed
28+
? `transform: skewY(${angle.value}deg);
29+
transform-origin: top right;`
30+
: `transform: skewY(-${angle.value}deg);
31+
transform-origin: top left;`}`

components/Generator/constants.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,6 @@ export const SEPARATOR_OPTIONS = {
7171
min: 0,
7272
max: 100,
7373
},
74-
top: {
75-
value: 50,
76-
min: 0,
77-
max: 50,
78-
},
7974
},
8075
[SEPARATORS.CURVED]: {
8176
reversed: false,

components/Generator/index.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as S from './styled'
77
import { SEPARATORS, SEPARATOR_OPTIONS } from './constants'
88

99
const Generator = props => {
10-
const defaultSeparator = SEPARATORS.WAVE
10+
const defaultSeparator = SEPARATORS.SKEWED
1111
const [active, setActive] = useState(defaultSeparator)
1212
const [options, setOptions] = useState(SEPARATOR_OPTIONS[defaultSeparator])
1313

@@ -17,6 +17,16 @@ const Generator = props => {
1717
}
1818

1919
const reversedClass = options.reversed ? 'reverse' : ''
20+
// TODO improve
21+
const TopElement = active === SEPARATORS.SEMI_CIRCLE
22+
? S.SemiCircle
23+
: active === SEPARATORS.SPIKES
24+
? S.Spikes
25+
: active === SEPARATORS.TRIANGLE
26+
? S.Triangle
27+
: active === SEPARATORS.CURVED
28+
? S.Curved
29+
: S.Top
2030

2131
return (
2232
<React.Fragment>
@@ -31,25 +41,23 @@ const Generator = props => {
3141
</a>
3242
</S.Header>
3343
<S.Container>
34-
<S.Top className={cn(active, reversedClass)} options={options}>
44+
<TopElement className={cn(active, reversedClass)} options={options}>
3545
<Controls
3646
options={options}
3747
setOptions={setOptions}
48+
active={active}
3849
/>
3950

4051
{ active === SEPARATORS.SKEWED &&
41-
<S.SkewBg
42-
className={reversedClass}
43-
angle={options.angle.value}>
44-
</S.SkewBg>
52+
<S.SkewBg options={options}></S.SkewBg>
4553
}
4654
{ active === SEPARATORS.WAVE &&
4755
<S.Wave
4856
className={reversedClass}
4957
curve={options.curve.value}>
5058
</S.Wave>
5159
}
52-
</S.Top>
60+
</TopElement>
5361
<S.Bottom>
5462
<S.Row>
5563
{ Object.entries(SEPARATORS).map(([key, val]) =>

components/Generator/styled.js

Lines changed: 93 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
import styled from 'styled-components'
2-
import { Card, FormControlLabel as MuiFormControlLabel } from '@material-ui/core'
3-
import { darkGrey } from '../../ui/constants'
1+
import styled, { css } from 'styled-components'
42
import _get from 'lodash/get'
3+
import {
4+
Card,
5+
TextareaAutosize,
6+
FormControlLabel as MuiFormControlLabel
7+
} from '@material-ui/core'
8+
import { darkGrey } from '../../ui/constants'
9+
import { generateSkewCss } from './codeGenerators'
510

611
export const Container = styled.main`
712
height: 100vh;
@@ -44,44 +49,50 @@ export const Top = styled(Section)`
4449
color: #fff;
4550
background: ${darkGrey};
4651
47-
&.curved {
48-
border-bottom-left-radius: 50% ${props => _get(props, 'options.curve.value')}%;
49-
border-bottom-right-radius: 50% ${props => _get(props, 'options.curve.value')}%;
50-
51-
&.reverse {
52-
border-bottom-left-radius: 0;
53-
border-bottom-right-radius: 0;
54-
55-
&::after {
56-
content: '';
57-
border-top-left-radius: 50% ${props => 100 - _get(props, 'options.curve.value') || 0}%; /* TODO fix */
58-
border-top-right-radius: 50% ${props => 100 - _get(props, 'options.curve.value') || 0}%;
59-
position: absolute;
60-
bottom: 0;
61-
width: 100%;
62-
background: #fff;
63-
height: 50px;
64-
}
65-
}
52+
&.skewed {
53+
background: transparent;
6654
}
55+
`
56+
57+
export const Curved = styled(Top)`
58+
border-bottom-left-radius: 50% ${props => _get(props, 'options.curve.value')}%;
59+
border-bottom-right-radius: 50% ${props => _get(props, 'options.curve.value')}%;
60+
61+
&.reverse {
62+
border-bottom-left-radius: 0;
63+
border-bottom-right-radius: 0;
6764
68-
&.spikes {
6965
&::after {
7066
content: '';
67+
border-top-left-radius: 50% ${props => 100 - _get(props, 'options.curve.value') || 0}%; /* TODO fix */
68+
border-top-right-radius: 50% ${props => 100 - _get(props, 'options.curve.value') || 0}%;
7169
position: absolute;
72-
right: 0;
73-
left: 0;
74-
top: 100%;
75-
z-index: 10;
76-
display: block;
77-
height: ${props => _get(props, 'options.size.value')}px;
78-
background-size: ${props => _get(props, 'options.size.value')}px 100%;
79-
background-image: linear-gradient(135deg, ${darkGrey} 25%, transparent 25%), linear-gradient(225deg, ${darkGrey} 25%, transparent 25%);
80-
background-position: ${props => _get(props, 'options.left.value')}%;
70+
bottom: 0;
71+
width: 100%;
72+
background: #fff;
73+
height: 50px;
8174
}
8275
}
76+
`
8377

84-
&.triangle::before {
78+
export const Spikes = styled(Top)`
79+
&::after {
80+
content: '';
81+
position: absolute;
82+
right: 0;
83+
left: 0;
84+
top: 100%;
85+
z-index: 10;
86+
display: block;
87+
height: ${props => _get(props, 'options.size.value')}px;
88+
background-size: ${props => _get(props, 'options.size.value')}px 100%;
89+
background-image: linear-gradient(135deg, ${darkGrey} 25%, transparent 25%), linear-gradient(225deg, ${darkGrey} 25%, transparent 25%);
90+
background-position: ${props => _get(props, 'options.left.value')}%;
91+
}
92+
`
93+
94+
export const Triangle = styled(Top)`
95+
&::before {
8596
content: '';
8697
position: absolute;
8798
bottom: 0;
@@ -92,15 +103,17 @@ export const Top = styled(Section)`
92103
height: ${props => _get(props, 'options.size.value')}px;
93104
transform:
94105
translateX(-50%)
95-
translateY(${props => _get(props, 'options.top.value')}%)
106+
translateY(50%)
96107
rotate(45deg);
97108
}
98109
99-
&.triangle.reverse::before {
110+
&.reverse::before {
100111
background: #fff;
101112
}
113+
`
102114

103-
&.semiCircle::before {
115+
export const SemiCircle = styled(Top)`
116+
&::before {
104117
position: absolute;
105118
content: '';
106119
left: ${props => _get(props, 'options.left.value')}%;
@@ -113,32 +126,16 @@ export const Top = styled(Section)`
113126
bottom: 0px;
114127
}
115128
116-
&.semiCircle.reverse::before {
129+
&.reverse::before {
117130
background: #fff;
118-
}
119-
120-
&.skewed {
121-
background: transparent;
131+
transform:
132+
translateX(-50%)
133+
translateY(${props => (_get(props, 'options.top.value') || 0) * -1 + 100}%);
122134
}
123135
`
124136

125137
export const SkewBg = styled.div`
126-
position: absolute;
127-
top: 0;
128-
bottom: 0;
129-
right: 0;
130-
left: 0;
131-
width: 100%;
132-
height: 100%;
133-
background: ${darkGrey};
134-
transform: ${props => `skewY(${props.angle}deg)`};
135-
transform-origin: top right;
136-
z-index: 0;
137-
138-
&.reverse {
139-
transform: ${props => `skewY(-${props.angle}deg)`};
140-
transform-origin: top left;
141-
}
138+
${props => generateSkewCss(props.options)}
142139
`
143140

144141
export const Wave = styled.div`
@@ -217,18 +214,35 @@ export const Row = styled.div`
217214

218215
export const Controls = styled(Card)`
219216
position: relative;
220-
background-color: #fff;
217+
background-color: rgba(255,255,255,0.7) !important;
221218
z-index: 20;
222219
223-
@media (max-height: 768px) { /* TODO figure out height */
220+
@media (max-height: 900px) {
224221
position: absolute;
225-
background-color: rgba(255,255,255,0.7) !important;
226222
top: 100px;
227223
}
228224
`
229225

230226
export const ControlContent = styled.div`
231227
padding: 10px;
228+
display: ${props => props.isVisible ? 'block' : 'none'};
229+
`
230+
231+
export const ControlToggle = styled.div`
232+
@media (min-height: 899px) {
233+
display: none;
234+
}
235+
236+
padding: 10px;
237+
border-top: 1px solid rgba(0,0,0,0.23);
238+
cursor: pointer;
239+
240+
> span {
241+
color: rgba(0, 0, 0, 0.54);
242+
display: flex;
243+
align-items: center;
244+
justify-content: center;
245+
}
232246
`
233247

234248
export const FormControlLabel = styled(MuiFormControlLabel)`
@@ -240,4 +254,23 @@ export const SliderContainer = styled.div`
240254
text-transform: capitalize;
241255
color: ${darkGrey};
242256
}
257+
`
258+
export const CodeArea = styled(TextareaAutosize)`
259+
width: 100%;
260+
margin-bottom: ${props => props.marginBottom ? '20px' : '0'};
261+
`
262+
263+
export const Copied = styled.span`
264+
display: inline-block;
265+
padding: 4px;
266+
margin-right: 5px;
267+
background: rgba(0,0,0,0.8);
268+
color: rgba(255,255,255,0.6);
269+
border-radius: 5px;
270+
opacity: 0;
271+
transition: opacity 0.3s;
272+
273+
${props => props.visible && css`
274+
opacity: 1;
275+
`}
243276
`

0 commit comments

Comments
 (0)