Skip to content

Commit 8d330d1

Browse files
authored
Merge pull request #7 from jinsoolim/addelements
Addelements
2 parents e799af5 + c2e17b8 commit 8d330d1

File tree

7 files changed

+187
-36
lines changed

7 files changed

+187
-36
lines changed

app/src/components/left/ComponentPanel.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ const ComponentPanel = (): JSX.Element => {
3232
setErrorMsg('Component name already exists.');
3333
} else if (type === 'letters') {
3434
setErrorMsg('Component name must start with a letter.');
35+
} else if (type === 'symbolsDetected') {
36+
setErrorMsg('Component name must not contain symbols.');
3537
}
3638
};
3739

@@ -81,11 +83,20 @@ const ComponentPanel = (): JSX.Element => {
8183
setCompName('');
8284
};
8385

86+
const alphanumeric = input => {
87+
let letterNumber = /^[0-9a-zA-Z]+$/;
88+
if (input.match(letterNumber)) return true;
89+
return false;
90+
}
91+
8492
const handleNameSubmit = () => {
8593
let letters = /[a-zA-Z]/;
8694
if (!compName.charAt(0).match(letters)) {
8795
triggerError('letters');
8896
return;
97+
} else if (!alphanumeric(compName)) {
98+
triggerError('symbolsDetected');
99+
return;
89100
} else if (compName.trim() === '') {
90101
triggerError('empty');
91102
return;

app/src/components/left/HTMLPanel.tsx

Lines changed: 166 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,68 @@ import React, { useState, useContext } from 'react';
22
import Grid from '@material-ui/core/Grid';
33
import { stateContext } from '../../context/context';
44
import HTMLItem from './HTMLItem';
5+
import { makeStyles } from '@material-ui/core/styles';
56

67
const HTMLPanel = (): JSX.Element => {
8+
const classes = useStyles();
9+
710
const [tag, setTag] = useState('');
811
const [name, setName] = useState('');
912
const [currentID, setCurrentID] = useState(12);
1013
const [state, dispatch] = useContext(stateContext);
14+
const [errorMsg, setErrorMsg] = useState('');
15+
const [errorStatus, setErrorStatus] = useState(false);
16+
1117

1218
const handleTagChange = (e: React.ChangeEvent<HTMLInputElement>) => {
19+
resetError();
1320
setTag(e.target.value);
14-
}
21+
};
1522

1623
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
24+
resetError();
1725
setName(e.target.value);
18-
}
26+
};
1927

20-
const handleSubmit = (e) => {
21-
e.preventDefault();
28+
const checkNameDupe = (inputName: String) => {
29+
let checkList = state.HTMLTypes.slice();
30+
31+
// checks to see if inputted comp name already exists
32+
let dupe = false;
33+
checkList.forEach(HTMLTag => {
34+
if ((HTMLTag.name.toLowerCase() === inputName.toLowerCase()) || (HTMLTag.tag.toLowerCase() === inputName.toLowerCase())) {
35+
dupe = true;
36+
}
37+
});
38+
return dupe;
39+
};
40+
41+
const triggerError = (type: String) => {
42+
setErrorStatus(true);
43+
if (type === 'empty') {
44+
setErrorMsg('Tag/ Tag name cannot be blank.');
45+
} else if (type === 'dupe') {
46+
setErrorMsg('Tag/ Tag name already exists.');
47+
} else if (type === 'letters') {
48+
setErrorMsg('Tag/ Tag name must start with a letter.');
49+
} else if (type === 'symbolsDetected') {
50+
setErrorMsg('Tag/ Tag name must not contain symbols.');
51+
}
52+
};
53+
54+
const resetError = () => {
55+
setErrorStatus(false);
56+
};
57+
58+
const createOption = (inputTag: String, inputName: String) => {
59+
// format name so first letter is capitalized and there are no whitespaces
60+
let inputNameClean = inputName.replace(/\s+/g, '');
61+
const formattedName = inputNameClean.charAt(0).toUpperCase() + inputNameClean.slice(1);
62+
// add new component to state
2263
const newElement = {
2364
id: currentID,
24-
tag,
25-
name,
65+
tag: inputTag,
66+
name: formattedName,
2667
style: {},
2768
placeHolderShort: name,
2869
placeHolderLong: '',
@@ -35,25 +76,56 @@ const HTMLPanel = (): JSX.Element => {
3576
setCurrentID(currentID + 1);
3677
setTag('');
3778
setName('');
38-
console.log("SUBMIT BUTTON CLICKED: ", newElement);
79+
};
80+
81+
const alphanumeric = input => {
82+
let letterNumber = /^[0-9a-zA-Z]+$/;
83+
if (input.match(letterNumber)) return true;
84+
return false;
85+
}
86+
87+
const handleSubmit = (e) => {
88+
e.preventDefault();
89+
let letters = /[a-zA-Z]/;
90+
if ((!tag.charAt(0).match(letters)) || (!name.charAt(0).match(letters))) {
91+
triggerError('letters');
92+
return;
93+
} else if (!alphanumeric(tag) || !alphanumeric(name)) {
94+
triggerError('symbolsDetected');
95+
return;
96+
} else if ((tag.trim() === '') || (name.trim() === '')) {
97+
triggerError('empty');
98+
return;
99+
} else if (checkNameDupe(tag) || checkNameDupe(name)) {
100+
triggerError('dupe');
101+
return;
102+
}
103+
createOption(tag, name);
104+
resetError();
39105
}
40106

41107
return (
42108
<div>
43109
<h4> HTML Elements</h4>
44-
<div>
45-
<form onSubmit={handleSubmit}>
46-
<h4>Create New Element: </h4>
47-
<label>
48-
Tag:
49-
<input type="text" name="Tag" value={tag} onChange={handleTagChange} />
50-
</label>
51-
<label>
52-
Tag Name:
53-
<input type="text" name="Tag Name" value={name} onChange={handleNameChange} />
54-
</label>
55-
<input type="submit" value="Add Element" />
56-
</form>
110+
<div className={classes.addComponentWrapper}>
111+
<div className={classes.inputWrapper} >
112+
<form onSubmit={handleSubmit} >
113+
<h4>Create New Element: </h4>
114+
<label className={classes.inputLabel}>
115+
Tag:
116+
<input color={'primary'} type="text" name="Tag" value={tag} onChange={handleTagChange} className={classes.input} />
117+
{errorStatus &&
118+
<span>{errorMsg}</span>}
119+
</label>
120+
<label className={classes.inputLabel}>
121+
Tag Name:
122+
<input color={'primary'} type="text" name="Tag Name" value={name} onChange={handleNameChange} className={classes.input} />
123+
{errorStatus &&
124+
<span>{errorMsg}</span>}
125+
</label>
126+
<input className={classes.button} color="primary" type="submit" value="Add Element" />
127+
</form>
128+
</div>
57129
</div>
58130
<Grid
59131
container
@@ -75,4 +147,78 @@ const HTMLPanel = (): JSX.Element => {
75147
);
76148
};
77149

150+
const useStyles = makeStyles({
151+
inputField: {
152+
marginTop: '15px'
153+
},
154+
inputWrapper: {
155+
// height: '115px',
156+
textAlign: 'center',
157+
display: 'flex',
158+
alignItems: 'center',
159+
justifyContent: 'space-between',
160+
// paddingLeft: '35px',
161+
marginBottom: '15px'
162+
},
163+
addComponentWrapper: {
164+
border: '1px solid rgba(70,131,83)',
165+
padding: '20px',
166+
margin: '20px'
167+
},
168+
rootCheckBox: {},
169+
rootCheckBoxLabel: {
170+
color: 'white'
171+
},
172+
panelWrapper: {
173+
width: '100%',
174+
marginTop: '15px'
175+
},
176+
panelWrapperList: {
177+
// maxHeight: '400px',
178+
minHeight: '120px',
179+
// overflowY: 'auto',
180+
marginLeft: '-15px',
181+
marginRight: '-15px'
182+
},
183+
panelSubheader: {
184+
textAlign: 'center',
185+
color: '#fff'
186+
},
187+
input: {
188+
color: '#fff',
189+
borderRadius: '5px',
190+
paddingLeft: '15px',
191+
paddingRight: '10px',
192+
whiteSpace: 'nowrap',
193+
overflowX: 'hidden',
194+
textOverflow: 'ellipsis',
195+
border: '1px solid rgba(51,235,145,0.75)',
196+
backgroundColor: 'rgba(255,255,255,0.15)'
197+
},
198+
inputLabel: {
199+
fontSize: '14px',
200+
zIndex: 20,
201+
color: '#fff',
202+
marginTop: '-10px'
203+
},
204+
btnGroup: {
205+
display: 'flex',
206+
flexDirection: 'column',
207+
paddingTop: '10px',
208+
marginLeft: '10px'
209+
},
210+
button: {
211+
fontSize: '1rem',
212+
height: '40px',
213+
maginTop: '10px',
214+
width: '100%',
215+
// border: '1px solid rgba(70,131,83)',
216+
backgroundColor: 'rgba(1,212,109,0.1)'
217+
},
218+
rootToggle: {
219+
color: '#01d46d',
220+
fontSize: '0.85rem'
221+
}
222+
});
223+
78224
export default HTMLPanel;

app/src/components/main/DirectChildComponent.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { ItemTypes } from '../../constants/ItemTypes';
1010
import { stateContext } from '../../context/context';
1111
import { combineStyles } from '../../helperFunctions/combineStyles';
1212
import IndirectChild from './IndirectChild';
13-
import HTMLTypes from '../../context/HTMLTypes';
1413
import globalDefaultStyle from '../../public/styles/globalDefaultStyles';
1514

1615
function DirectChildComponent({ childId, type, typeId, style }: ChildElement) {
@@ -104,7 +103,7 @@ function DirectChildComponent({ childId, type, typeId, style }: ChildElement) {
104103
// if the HTML element has children, then also render its children
105104
// get the default style/placeholder value for that type of HTML element
106105
// combine the default style of that HTML element and combine in with the custom styles applied to that element
107-
const HTMLType: HTMLType = HTMLTypes.find(
106+
const HTMLType: HTMLType = state.HTMLTypes.find(
108107
(type: HTMLType) => type.id === child.typeId
109108
);
110109
const HTMLDefaultStyle = HTMLType.style;

app/src/components/main/DirectChildHTMLNestable.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useDrag, useDrop, DropTargetMonitor } from 'react-dnd';
44
import { ItemTypes } from '../../constants/ItemTypes';
55
import { stateContext } from '../../context/context';
66
import { combineStyles } from '../../helperFunctions/combineStyles';
7-
import HTMLTypes from '../../context/HTMLTypes';
87
import globalDefaultStyle from '../../public/styles/globalDefaultStyles';
98
import renderChildren from '../../helperFunctions/renderChildren';
109

@@ -20,7 +19,7 @@ function DirectChildHTMLNestable({
2019

2120
// find the HTML element corresponding with this instance of an HTML element
2221
// find the current component to render on the canvas
23-
const HTMLType: HTMLType = HTMLTypes.find(
22+
const HTMLType: HTMLType = state.HTMLTypes.find(
2423
(type: HTMLType) => type.id === typeId
2524
);
2625

app/src/components/right/DeleteProjects.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ const useStyles = makeStyles({
118118
fontSize: '1em',
119119
minWidth: '300px',
120120
marginTop: '10px',
121-
marginBotton: '10px'
121+
marginBottom: '10px'
122122
},
123123
avatar: {
124124
backgroundColor: blue[100],

app/src/helperFunctions/generateCode.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ declare global {
77
}
88
}
99

10-
// generate code based on the component heirarchy
10+
// generate code based on the component hierarchy
1111
const generateUnformattedCode = (
1212
comps: Component[],
1313
componentId: number,
@@ -24,7 +24,7 @@ const generateUnformattedCode = (
2424

2525
const isRoot = rootComponents.includes(componentId);
2626

27-
// get metadata for each child (e.g. the name/tag of the component/elemnt)
27+
// get metadata for each child (e.g. the name/tag of the component/element)
2828
const getEnrichedChildren = (currentComponent: Component | ChildElement) => {
2929
const enrichedChildren = currentComponent.children.map((elem: any) => {
3030
const child = { ...elem };
@@ -38,8 +38,6 @@ const generateUnformattedCode = (
3838
return child;
3939
} else if (child.type === 'HTML Element') {
4040
const referencedHTML = HTMLTypes.find(elem => elem.id === child.typeId);
41-
console.log("ARRAY OF HTMLS: ", HTMLTypes);
42-
console.log("REF HTML: ", referencedHTML);
4341
child['tag'] = referencedHTML.tag;
4442
if (referencedHTML.tag === 'div') {
4543
child.children = getEnrichedChildren(child);
@@ -103,7 +101,7 @@ const generateUnformattedCode = (
103101
return `<${child.tag}${formatStyles(child.style)}></${child.tag}>`;
104102
}
105103
}
106-
// route links are only a next.js feature. if the user creates a rotue link and then switches projects, generate code for a normal link instead
104+
// route links are only a next.js feature. if the user creates a route link and then switches projects, generate code for a normal link instead
107105
else if (child.type === 'Route Link') {
108106
return projectType === 'Next.js'
109107
? `<div><Link href="/${child.name}"><a>${child.name}</a></Link></div>`
@@ -113,7 +111,7 @@ const generateUnformattedCode = (
113111
.join('\n')}`;
114112
};
115113

116-
// format styles stored in object to match React's inline style format
114+
// format styles stored in object to match React inline style format
117115
const formatStyles = (styleObj: any) => {
118116
if (Object.keys(styleObj).length === 0) return ``;
119117
const formattedStyles = [];
@@ -159,7 +157,7 @@ const generateUnformattedCode = (
159157
${
160158
classBased
161159
? `class ${currentComponent.name} extends Component {`
162-
: `const ${currentComponent.name} = (props) => {`
160+
: `const ${currentComponent.name} = (props): JSX.Element => {`
163161
}
164162
${
165163
stateful && !classBased
@@ -195,7 +193,7 @@ const generateUnformattedCode = (
195193
import Head from 'next/head'
196194
${links ? `import Link from 'next/link'` : ``}
197195
198-
const ${currentComponent.name} = (props) => {
196+
const ${currentComponent.name} = (props): JSX.Element => {
199197
200198
const [value, setValue] = useState("INITIAL VALUE");
201199
@@ -239,7 +237,7 @@ const formatCode = (code: string) => {
239237
}
240238
};
241239

242-
// generate code based on component heirarchy and then return the rendered code
240+
// generate code based on component hierarchy and then return the rendered code
243241
const generateCode = (
244242
components: Component[],
245243
componentId: number,

app/src/reducers/componentReducer.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,10 +433,8 @@ const reducer = (state: State, action: Action) => {
433433
}
434434

435435
case 'ADD ELEMENT': {
436-
console.log("REDUCER HIT");
437436
const HTMLTypes = [...state.HTMLTypes];
438437
HTMLTypes.push(action.payload);
439-
console.log("MY NEW ARRAY: ", HTMLTypes);
440438
return {
441439
...state,
442440
HTMLTypes

0 commit comments

Comments
 (0)