Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F10360256
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rSEALPAGE Sealpage
Attached
Detach File
Event Timeline
Log In to Comment