Page MenuHomeSealhub

No OneTemporary

diff --git a/admin-panel/body-page-editor/body-page-editor.jsx b/admin-panel/body-page-editor/body-page-editor.jsx
index 48a6f35..2fb6824 100644
--- a/admin-panel/body-page-editor/body-page-editor.jsx
+++ b/admin-panel/body-page-editor/body-page-editor.jsx
@@ -1,110 +1,179 @@
-import React, { Component } from 'react';
-import List from './list';
+import React, { Component, useReducer } from 'react';
+import ElementEditor from './element-editor';
import Preview from './preview';
-import components_map from '../../components/components.map';
+import SelectComponent from './select-component';
-export default class BodyPageEditor extends Component {
- constructor(props) {
- super(props);
+import components_map from '../../components/components.map';
- this.state = {
- createdComponents: [],
- renderedHtml: '',
- componentType: '',
+function reducer(state, action) {
+ switch (action.type) {
+ case 'addElement':
+ return {
+ ...state,
+ componentToCreate: null,
+ elements: state.elements.concat([
+ [components_map[state.componentToCreate], {}],
+ ]),
};
- this.handleChange = this.handleChange.bind(this);
- this.handleSubmit = this.handleSubmit.bind(this);
- this.renderPreview = this.renderPreview.bind(this);
- }
-
- componentDidMount() {
- console.log(components_map.Markdown('# Test'));
- }
-
- handleChange(event) {
- this.setState({ componentType: event.target.value });
- }
-
- handleSubmit(event) {
- let args = [];
-
- for (let element of event.target.children) {
- if (element.type !== 'submit') args.push(element.value);
- element.value = '';
- }
- let createdComponents = this.state.createdComponents;
- createdComponents.push({
- component: this.state.componentType,
- args,
- });
+ case 'setElementProps':
+ state.elements[action.elementIndex][1] = action.newProps;
- this.setState({
- createdComponents,
- });
- }
-
- async renderPreview() {
- let html = '';
- for (const segment of this.state.createdComponents) {
- // TO DO: push data from segment element to function html.js
- html += await components_map[segment.component](...segment.args);
- }
- console.log(html);
- return html;
- }
-
- createComponentForm() {
- let form = [];
- console.log('create component form');
-
- for (
- let i = 0;
- i < components_map[this.state.componentType].length;
- i++
- ) {
- // TO DO: we have to consider using typescript for components or documented code of parameters to sealpage components
- form.push(
- <input type="text" id={`${this.state.componentType}-${i}`} />
- );
- }
- return form;
- }
+ return {
+ ...state,
+ elements: state.elements,
+ };
- render() {
- console.log(components_map.Markdown.length);
-
- return (
- <React.Fragment>
- <h2>Body Page Editor</h2>
- <div style={{ display: 'flex', flexFlow: 'row' }}>
- <List createdComponents={this.state.createdComponents} />
- <Preview renderedHtml={this.state.renderedHtml} />
- </div>
-
- <label htmlFor="select-component">Select a component: </label>
- <select id="select-component" onChange={this.handleChange}>
- <option value="">--Please choose an option--</option>
- {Object.keys(components_map).map(component => {
- return (
- <option key={component} value={component}>
- {component}
- </option>
- );
- })}
- </select>
-
- <div>Selected component: {this.state.componentType}</div>
-
- <form onSubmit={this.handleSubmit}>
- {this.state.componentType
- ? this.createComponentForm()
- : null}
- <input type="submit" value="Submit component" />
- </form>
-
- <button onClick={this.renderPreview}>Render preview</button>
- </React.Fragment>
- );
+ case 'setComponentToCreate':
+ return {
+ ...state,
+ componentToCreate: action.componentToCreate,
+ };
}
}
+export default function bodyPageEditor() {
+ const [state, dispatch] = useReducer(reducer, {
+ componentToCreate: '',
+ elements: [],
+ });
+
+ return (
+ <React.Fragment>
+ <h2>Body Page Editor</h2>
+ <div style={{ display: 'flex', flexFlow: 'row' }}>
+ {state.elements.map(([component, componentProps], index) => (
+ <ElementEditor
+ key={index}
+ component={component}
+ componentProps={componentProps}
+ onChange={newProps =>
+ dispatch({
+ type: 'setElementProps',
+ elementIndex: index,
+ newProps,
+ })
+ }
+ />
+ ))}
+
+ <Preview elements={state.elements} />
+ </div>
+
+ <div>{JSON.stringify(state.elements)}</div>
+
+ <SelectComponent
+ value={state.componentToCreate || ''}
+ onChange={value =>
+ dispatch({
+ type: 'setComponentToCreate',
+ componentToCreate: value,
+ })
+ }
+ />
+ <button
+ disabled={!state.componentToCreate}
+ onClick={() => {
+ dispatch({ type: 'addElement' });
+ }}
+ >
+ Add element
+ </button>
+ </React.Fragment>
+ );
+}
+
+// export default class BodyPageEditor extends Component {
+// constructor(props) {
+// super(props);
+
+// this.state = {
+// createdComponents: [],
+// renderedHtml: '',
+// componentType: '',
+// };
+// this.handleChange = this.handleChange.bind(this);
+// this.handleSubmit = this.handleSubmit.bind(this);
+// this.renderPreview = this.renderPreview.bind(this);
+// }
+
+// // componentDidMount() {
+// // console.log(components_map.Markdown('# Test'));
+// // }
+
+// handleChange(event) {
+// this.setState({ componentType: event.target.value });
+// }
+
+// handleSubmit(event) {
+// let args = [];
+
+// for (let element of event.target.children) {
+// if (element.type !== 'submit') args.push(element.value);
+// element.value = '';
+// }
+
+// let createdComponents = this.state.createdComponents;
+// createdComponents.push({
+// component: this.state.componentType,
+// args,
+// });
+
+// this.setState({
+// createdComponents,
+// });
+// }
+
+// async renderPreview() {
+// let html = '';
+// for (const segment of this.state.createdComponents) {
+// // TO DO: push data from segment element to function html.js
+// html += await components_map[segment.component](...segment.args);
+// }
+// console.log(html);
+// return html;
+// }
+
+// createComponentForm() {
+// let form = [];
+// console.log('create component form');
+
+// for (
+// let i = 0;
+// i < components_map[this.state.componentType].length;
+// i++
+// ) {
+// // TO DO: we have to consider using typescript for components or documented code of parameters to sealpage components
+// form.push(
+// <input type="text" id={`${this.state.componentType}-${i}`} />
+// );
+// }
+// return form;
+// }
+
+// render() {
+// console.log(components_map.Markdown.length);
+
+// return (
+// <React.Fragment>
+// <h2>Body Page Editor</h2>
+// <div style={{ display: 'flex', flexFlow: 'row' }}>
+// <List createdComponents={this.state.createdComponents} />
+// <Preview renderedHtml={this.state.renderedHtml} />
+// </div>
+
+// <label htmlFor="select-component">Select a component: </label>
+
+// <div>Selected component: {this.state.componentType}</div>
+
+// <form onSubmit={this.handleSubmit}>
+// {this.state.componentType
+// ? this.createComponentForm()
+// : null}
+// <input type="submit" value="Submit component" />
+// </form>
+
+// <button onClick={this.renderPreview}>Render preview</button>
+// </React.Fragment>
+// );
+// }
+// }
diff --git a/admin-panel/body-page-editor/element-editor.jsx b/admin-panel/body-page-editor/element-editor.jsx
new file mode 100644
index 0000000..5802284
--- /dev/null
+++ b/admin-panel/body-page-editor/element-editor.jsx
@@ -0,0 +1,37 @@
+import React, { Component } from 'react';
+
+export default function ElementEditor({ component, componentProps, onChange }) {
+ function createControls() {
+ let controls = [];
+
+ for (const prop in component.propsControls) {
+ controls.push(
+ component.propsControls[prop]({
+ name: prop,
+ value: componentProps[prop],
+ onChange: newValue => {
+ onChange({ ...componentProps, [prop]: newValue });
+ },
+ })
+ );
+ }
+
+ return controls;
+ }
+
+ return (
+ <div
+ style={{
+ display: 'flex',
+ flexFlow: 'column',
+ width: '30rem',
+ height: 'auto',
+ padding: '1rem',
+ margin: '1rem',
+ backgroundColor: '#fdf6e3',
+ }}
+ >
+ {createControls()}
+ </div>
+ );
+}
diff --git a/admin-panel/body-page-editor/list.jsx b/admin-panel/body-page-editor/list.jsx
deleted file mode 100644
index 4ebecc7..0000000
--- a/admin-panel/body-page-editor/list.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import React, { Component } from 'react';
-
-export default class List extends Component {
- render() {
- return (
- <div
- style={{
- display: 'flex',
- flexFlow: 'column',
- width: '30rem',
- height: 'auto',
- padding: '1rem',
- margin: '1rem',
- backgroundColor: '#fdf6e3',
- }}
- >
- Body content
- </div>
- );
- }
-}
diff --git a/admin-panel/body-page-editor/preview.jsx b/admin-panel/body-page-editor/preview.jsx
index ce6d2a3..9069a76 100644
--- a/admin-panel/body-page-editor/preview.jsx
+++ b/admin-panel/body-page-editor/preview.jsx
@@ -1,18 +1,36 @@
-import React, { Component } from 'react';
+import React, { Component, useState, useEffect } from 'react';
+async function renderPreview(elements) {
+ let html = '';
+ console.log('elements', elements);
+
+ for (const [component, componentProps] of elements) {
+ console.log(component, componentProps);
+
+ html += await component.render(componentProps);
+ }
+ console.log(html);
+ return html;
+}
export default function Preview(props) {
+ const [html, setHtml] = useState('');
+
+ useEffect(() => {
+ renderPreview(props.elements).then(setHtml);
+ });
+
return (
<div
style={{
display: 'flex',
flexFlow: 'column',
width: '30rem',
height: 'auto',
padding: '1rem',
margin: '1rem',
backgroundColor: '#f1f1f1',
}}
- dangerouslySetInnerHTML={{ __html: props.renderedHtml }}
+ dangerouslySetInnerHTML={{ __html: html }}
/>
);
}
diff --git a/admin-panel/body-page-editor/select-component.jsx b/admin-panel/body-page-editor/select-component.jsx
new file mode 100644
index 0000000..1cb08ac
--- /dev/null
+++ b/admin-panel/body-page-editor/select-component.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import components_map from '../../components/components.map.js';
+
+export default function selectComponent(props) {
+ return (
+ <select
+ id="select-component"
+ onChange={e => props.onChange(e.target.value)}
+ value={props.value}
+ >
+ <option value="">--Please choose an option--</option>
+
+ {Object.keys(components_map).map(component => {
+ return (
+ <option key={component} value={component}>
+ {component}
+ </option>
+ );
+ })}
+ </select>
+ );
+}
diff --git a/admin-panel/form-controls/form-controls.jsx b/admin-panel/form-controls/form-controls.jsx
index decda6e..fab49f3 100644
--- a/admin-panel/form-controls/form-controls.jsx
+++ b/admin-panel/form-controls/form-controls.jsx
@@ -1,6 +1,7 @@
import text from './text.jsx';
import date from './date.jsx';
+import textarea from './textarea';
-const FormControls = { text, date, slug: text };
+const FormControls = { text, date, slug: text, textarea };
export default FormControls;
diff --git a/admin-panel/form-controls/textarea.jsx b/admin-panel/form-controls/textarea.jsx
new file mode 100644
index 0000000..859e271
--- /dev/null
+++ b/admin-panel/form-controls/textarea.jsx
@@ -0,0 +1,13 @@
+const React = require('react');
+
+export default function textarea(props) {
+ return (
+ <textarea
+ name={props.name}
+ id={props.name}
+ value={props.value}
+ onChange={e => props.onChange(e.target.value)}
+ required={props.required}
+ />
+ );
+}
diff --git a/components/component.class.js b/components/component.class.js
new file mode 100644
index 0000000..00440b9
--- /dev/null
+++ b/components/component.class.js
@@ -0,0 +1,26 @@
+export default class Component {
+ constructor({ renderFn, propsControls }) {
+ if (typeof renderFn !== 'function') {
+ throw new Error('renderFn must be a function');
+ }
+
+ if (typeof propsControls !== 'object') {
+ throw new Error('propsControls must be an object');
+ }
+
+ for (let item in propsControls) {
+ if (typeof propsControls[item] !== 'function') {
+ throw new Error(
+ `${propsControls[item]} formControl is not a function`
+ );
+ }
+ }
+
+ this.renderFn = renderFn;
+ this.propsControls = propsControls;
+ }
+
+ async render(propsControls) {
+ return await this.renderFn(propsControls);
+ }
+}
diff --git a/components/markdown/markdown.html.js b/components/markdown/markdown.html.js
index 4b5abc2..611fd3e 100644
--- a/components/markdown/markdown.html.js
+++ b/components/markdown/markdown.html.js
@@ -1,3 +1,14 @@
-const marked = require('marked');
+import Component from '../component.class';
+import formControls from '../../admin-panel/form-controls/form-controls';
+import marked from 'marked';
-module.exports = markdown_source => marked(markdown_source);
+const Markdown = new Component({
+ renderFn: ({ markdown_source }) => {
+ return marked(markdown_source || '');
+ },
+ propsControls: {
+ markdown_source: formControls.textarea,
+ },
+});
+
+export default Markdown;
diff --git a/components/navbar/navbar.html.js b/components/navbar/navbar.html.js
index eacd8ce..3cc952a 100644
--- a/components/navbar/navbar.html.js
+++ b/components/navbar/navbar.html.js
@@ -1,5 +1,15 @@
-module.exports = ({ title }) => {
- return /* HTML */ `
- <nav>${title}</nav>
- `;
-};
+import Component from '../component.class';
+import formControls from '../../admin-panel/form-controls/form-controls';
+
+const Navbar = new Component({
+ renderFn: ({ title }) => {
+ return /* HTML */ `
+ <nav>${title}</nav>
+ `;
+ },
+ propsControls: {
+ title: formControls.text,
+ },
+});
+
+export default Navbar;

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 8, 05:51 (1 d, 1 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1034075
Default Alt Text
(13 KB)

Event Timeline