Skip to content

Commit c5debc1

Browse files
Merge pull request #5 from oslabs-beta/stephen-feature
Code preview functional
2 parents 57c97eb + e52b610 commit c5debc1

File tree

16 files changed

+260
-69
lines changed

16 files changed

+260
-69
lines changed

app/electron/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ async function createWindow() {
8080
// web workers will not have access to node
8181
nodeIntegrationInWorker: false,
8282
// disallow experimental feature to allow node.js support in sub-frames (i-frames/child windows)
83-
nodeIntegrationInSubFrames: false,
83+
nodeIntegrationInSubFrames: true,
8484
// runs electron apis and preload script in a separate JS context
8585
// separate context has access to document/window but has it's own built-ins and is isolate from changes to global environment by located page
8686
// Electron API only available from preload, not loaded page

app/src/components/bottom/CodePreview.tsx

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,29 @@ import 'ace-builds/src-noconflict/theme-terminal';
1212
import { Component } from '../../interfaces/Interfaces';
1313
import useResizeObserver from '../../tree/useResizeObserver';
1414
import { string } from 'prop-types';
15+
import { unpkgPathPlugin } from '../../plugins/unpkg-path-plugin';
16+
import { fetchPlugin } from '../../plugins/fetch-plugin';
17+
import * as esbuild from 'esbuild-wasm';
18+
import { useSelector, useDispatch } from 'react-redux';
19+
import { store } from './../../index';
1520

1621
const CodePreview: React.FC<{
1722
theme: string | null;
1823
setTheme: any | null;
1924
}> = ({ theme, setTheme }) => {
25+
26+
27+
const ref = useRef<any>();
28+
const iframe = useRef<any>();
29+
30+
31+
const startService = async () => {
32+
ref.current = await esbuild.startService({
33+
worker: true,
34+
wasmURL: 'https://unpkg.com/[email protected]/esbuild.wasm',
35+
})
36+
}
37+
2038
const wrapper = useRef();
2139
const dimensions = useResizeObserver(wrapper);
2240
const { width, height } =
@@ -27,14 +45,58 @@ const CodePreview: React.FC<{
2745
const currentComponent = state.components.find(
2846
(elem: Component) => elem.id === state.canvasFocus.componentId
2947
);
48+
const [input, setInput] = useState(currentComponent.code);
49+
50+
console.log('this is state', state.components)
51+
console.log('currentcomponent.code', currentComponent.code)
52+
3053

3154
const handleCodeSnipChange = (val) => {
3255
currentComponent.code = val;
3356
};
3457

58+
useEffect(() => {
59+
startService();
60+
}, []);
61+
3562
useEffect(() => {
3663
setDivHeight(height);
3764
}, [height])
65+
66+
useEffect(() => {
67+
setInput(currentComponent.code)
68+
}, [state])
69+
70+
71+
const handleChange = (data) => {
72+
setInput(data)
73+
console.log('line 69',input)
74+
};
75+
76+
const handleClick = async () => {
77+
// setInput(currentComponent.code)
78+
// console.log('currentComponent.code', currentComponent.code)
79+
if(!ref.current) {
80+
return;
81+
}
82+
const result = await ref.current.build({
83+
entryPoints: ['index.js'],
84+
bundle: true,
85+
write: false,
86+
plugins: [
87+
unpkgPathPlugin(),
88+
fetchPlugin(input)
89+
],
90+
define: {
91+
'process.env.NODE_ENV': '"development"',
92+
global: 'window'
93+
}
94+
})
95+
console.log('this is input',input)
96+
store.dispatch({type: "SAVE", payload: result.outputFiles[0].text});
97+
}
98+
99+
38100
return (
39101
<div
40102
ref={wrapper}
@@ -48,16 +110,21 @@ const CodePreview: React.FC<{
48110
mode="javascript"
49111
theme="monokai"
50112
width="100%"
51-
height="100%"
52-
onChange={handleCodeSnipChange}
53-
value={currentComponent.code}
113+
height="70%"
114+
onChange={handleChange}
115+
// value={currentComponent.code}
116+
value={input}
54117
name="Code_div"
55118
readOnly={false}
56119
fontSize={16}
57120
tabSize={2}
58121
/>
122+
<button onClick={() => handleClick()}>Fetch</button>
59123
</div>
60124
);
61125
};
62126

63127
export default CodePreview;
128+
129+
130+

app/src/components/form/Selector.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const FormSelector = (props): JSX.Element => {
1313
})
1414
return (
1515
<div className={props.classes.configRow}>
16+
1617
<div className={props.isThemeLight ? `${props.classes.configType} ${props.classes.lightThemeFontColor}` : `${props.classes.configType} ${props.classes.darkThemeFontColor}`}>
1718
<h3>{props.title}</h3>
1819
</div>

app/src/components/left/HTMLItem.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ const HTMLItem : React.FC<{
122122
// updated the id's to reflect the new element types input and label
123123
return ( // HTML Elements
124124
<Grid item xs={5} key={`html-g${name}`}>
125+
125126
{ id <= 18 &&
126127
<div ref={drag} className={isThemeLight ? `${classes.HTMLPanelItem} ${classes.lightThemeFontColor}` : `${classes.HTMLPanelItem} ${classes.darkThemeFontColor}`} id="HTMLItem">
127128
<h3>{name}</h3>

app/src/components/main/Canvas.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ function Canvas() {
8080
const canvasStyle = combineStyles(defaultCanvasStyle, currentComponent.style);
8181
return (
8282
<div ref={drop} style={canvasStyle} onClick={onClickHandler}>
83-
{/* currentComponent is the selected component on Left Panel (eg: App or Index with green dot to the left) */}
84-
{renderChildren(currentComponent.children)}
83+
84+
{renderChildren(currentComponent.children)}
8585
</div>
8686
);
8787
}

app/src/components/main/CanvasContainer.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ function CanvasContainer() {
1111

1212
return (
1313
<div style={canvasContainerStyle}>
14+
1415
<Canvas />
1516
</div>
1617
);

app/src/components/main/DemoRender.tsx

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,48 @@
11

22
import React, {
3-
useState, useCallback, useContext, useEffect,
3+
useState, useCallback, useContext, useEffect, useRef
44
} from 'react';
5+
import ReactDOM from 'react-dom';
56
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
67
import Button from '@material-ui/core/Button';
78
import Box from '@material-ui/core/Box';
89
import StateContext from '../../context/context';
910
import cssRefresher from '../../helperFunctions/cssRefresh';
10-
11+
import {store} from '../../../src/index';
12+
import { useSelector } from 'react-redux';
1113
// DemoRender is the full sandbox demo of our user's custom built React components. DemoRender references the design specifications stored in state to construct
1214
// real react components that utilize hot module reloading to depict the user's prototype application.
1315
const DemoRender = (props): JSX.Element => {
16+
17+
const iframe = useRef<any>();
1418
const [components, setComponents] = useState([]);
1519
const [state, dispatch] = useContext(StateContext);
20+
const [codeRender, setCodeRender] = useState('')
1621
const demoContainerStyle = {
1722
width: '100%',
1823
backgroundColor: '#FBFBFB',
1924
border: '2px Solid grey',
2025
};
2126

22-
// This function is the heart of DemoRender it will take the array of components stored in state and dynamically construct the desired React component for the live demo
23-
// Material UI is utilized to incorporate the apporpriate tags with specific configuration designs as necessitated by HTML standards.
27+
let code = useSelector((state) => state.code);
28+
29+
const html = `
30+
<html>
31+
<head></head>
32+
<body>
33+
<div id='app'></div>
34+
<script>
35+
window.addEventListener('message', (e) => {
36+
console.log(e)
37+
eval(e.data);
38+
}, false);
39+
</script>
40+
</body>
41+
</html>
42+
`;
43+
44+
// This function is the heart of DemoRender it will take the array of components stored in state and dynamically construct the desired React component for the live demo
45+
// Material UI is utilized to incorporate the apporpriate tags with specific configuration designs as necessitated by HTML standards.
2446
const componentBuilder = (array: object, key: number = 0) => {
2547
const componentsToRender = [];
2648
for (const element of array) {
@@ -48,7 +70,7 @@ const DemoRender = (props): JSX.Element => {
4870
}
4971
return componentsToRender;
5072
};
51-
73+
5274
useEffect(() => {
5375
const focusIndex = state.canvasFocus.componentId - 1;
5476
const childrenArray = state.components[focusIndex].children;
@@ -61,14 +83,23 @@ const DemoRender = (props): JSX.Element => {
6183
}, [])
6284

6385

86+
useEffect(() => {
87+
88+
console.log("code changed", code);
89+
setCodeRender(code)
90+
iframe.current.contentWindow.postMessage(code, '*');
91+
92+
}, [code])
93+
6494
return (
65-
<Router>
6695
<div id={'renderFocus'} style={demoContainerStyle}>
67-
{components.map((component, index) => component)}
68-
</div>
69-
</Router>
96+
97+
98+
<iframe ref={iframe} sandbox='allow-scripts' srcDoc={html} width='500px' height='500px'/>
99+
70100

101+
</div>
71102
);
72103
};
73104

74-
export default DemoRender;
105+
export default DemoRender;

app/src/helperFunctions/generateCode.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const generateUnformattedCode = (
4949
let links: boolean = false;
5050

5151
const isRoot = rootComponents.includes(componentId);
52-
let importReactRouter = false;;
52+
let importReactRouter = false;
5353

5454
// returns an array of objects which may include components, html elements, and/or route links
5555
const getEnrichedChildren = (currentComponent: Component | ChildElement) => {
@@ -287,38 +287,31 @@ const generateUnformattedCode = (
287287
// classic react code
288288
if (projectType === 'Classic React') {
289289
return `
290-
${`import React, { useState, createContext, useContext } from 'react';`}
290+
${`import React, { useState, useEffect} from 'react';`}
291+
${`import ReactDOM from 'react-dom';`}
291292
${importReactRouter ? `import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';`: ``}
292293
${importsMapped}
293294
${importContext}
294295
${providers}
295296
${context}
296-
${`const ${currComponent.name} = (props: any): JSX.Element => {`}
297-
${` const [value, setValue] = useState<any | undefined>("INITIAL VALUE");${writeStateProps(currComponent.useStateCodes)}`}
298-
${
299-
isRoot && currComponent.stateProps.length !== 0
300-
? ` const ${currComponent.name}Context = createContext(${createState(currComponent.stateProps)});`
301-
: ``
302-
}
297+
${`const ${currComponent.name} = (props) => {`}
298+
${` const [value, setValue] = useState("");${writeStateProps(currComponent.useStateCodes)}`}
299+
303300
${!importReactRouter
304301
? ` return (
305-
<${currComponent.name}Context.Provider value="">
306302
<div className="${currComponent.name}" ${formatStyles(currComponent)}>
307303
\t${writeNestedElements(enrichedChildren)}
308304
</div>
309-
</${currComponent.name}Context.Provider>
310305
);`
311306
: ` return (
312-
<${currComponent.name}Context.Provider value="">
313307
<Router>
314308
<div className="${currComponent.name}" ${formatStyles(currComponent)}>
315309
\t${writeNestedElements(enrichedChildren)}
316310
</div>
317311
</Router>
318-
</${currComponent.name}Context.Provider>
319312
);`}
320313
${`}\n`}
321-
export default ${currComponent.name};
314+
ReactDOM.render(<${currComponent.name} />, document.querySelector('#app'));
322315
`;
323316
}
324317
// next.js component code

app/src/index.js

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
} from 'react-router-dom';
88
import 'babel-polyfill';
99
import React from 'react';
10+
import { createStore } from 'redux';
11+
import { Provider } from 'react-redux';
1012
import ReactDOM from 'react-dom';
1113
import Cookies from 'js-cookie';
1214
import App from './components/App.tsx';
@@ -22,6 +24,24 @@ const client = new ApolloClient({
2224
uri: 'https://reactype-caret.herokuapp.com/graphql',
2325
cache: new InMemoryCache()
2426
});
27+
const initialState = {code: `
28+
import React from 'react';
29+
import ReactDOM from 'react-dom';
30+
const App = () => <h1>Hello World!</h1>
31+
32+
ReactDOM.render(<App />, document.querySelector('#app'));`}
33+
const rootReducer = (state = initialState, action) => {
34+
console.log('action', action);
35+
switch (action.type) {
36+
case 'SAVE':
37+
return {...state, code:action.payload};
38+
default:
39+
return state;
40+
}
41+
42+
}
43+
44+
export const store = createStore(rootReducer)
2545

2646
const PrivateRoute = ({ component: Component, ...rest }) => (
2747
<Route
@@ -38,17 +58,19 @@ const PrivateRoute = ({ component: Component, ...rest }) => (
3858

3959
ReactDOM.render(
4060
<ApolloProvider client={client}>
41-
<Router>
42-
<Switch>
43-
<Route exact path="/login" component={SignIn} />
44-
<Route exact path="/signup" component={SignUp} />
45-
<Route exact path="/password" component={FBPassWord} />
46-
<PrivateRoute exact path="/" component={App} />
47-
<Route exact path="/dashboard" component={ProjectDashboard} />
48-
<Route exact path="/tutorial" component={Tutorial} />
49-
<Route exact path="/tutorialPage/:learn" component={TutorialPage} />
50-
</Switch>
51-
</Router>
61+
<Provider store={store}>
62+
<Router>
63+
<Switch>
64+
<Route exact path="/login" component={SignIn} />
65+
<Route exact path="/signup" component={SignUp} />
66+
<Route exact path="/password" component={FBPassWord} />
67+
<PrivateRoute exact path="/" component={App} />
68+
<Route exact path="/dashboard" component={ProjectDashboard} />
69+
<Route exact path="/tutorial" component={Tutorial} />
70+
<Route exact path="/tutorialPage/:learn" component={TutorialPage} />
71+
</Switch>
72+
</Router>
73+
</Provider>
5274
</ ApolloProvider>,
5375
document.getElementById('app'),
5476
);

0 commit comments

Comments
 (0)