2
\$\begingroup\$

What do you think of my markdown previewer, which uses the marked library? I'm asking because I'm new to React. And also what do you think of app itself? Did I use React correctly and properly?

HTML:

<div id="root"></div>

CSS:

$position: absolute;
$percentage: 100%;
$color: whitesmoke;
$car: auto;

@import url("//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css");
@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css");

.btn1 {
  position: $position;
  bottom: -30px;
  left: 51.3%;
  z-index: 999;
  background-color: $color;
  border: 1px solid gray;
  color: aqua;
}

#root {
  width: $percentage;
  //font-size: 1.5em;
}

body,
html {
  height: $percentage;
}

body {
  background-color: $color;
  background-image: url("../images/react1.png");
  background-repeat: no-repeat;
  background-size: $car;
  background-position: center bottom;
  overflow: hidden;
}

.grid-container {
  display: grid;
  grid-template-columns: 50% 50%;
  background-color: $color;
  padding: 10px;
  grid-gap: 15px;
  width: $percentage;
  grid-template-rows: 30px 25px 98%;
}

.grid-item {
  text-align: center;
  margin-top: 10px !important;
  padding-top: 10px !important;
}

#inner2 {
  padding-left: 20px;
  padding-right: 25px;
  border-bottom: 15px solid #d6e9c6;
  padding-bottom: 55px;
  background-color: #fcf8e3;
  width: $percentage;
  margin-left: $car;
  margin-right: $car;
  position: $position;
  top: 0px;
  left: 0px;
  height: $percentage;
  min-height: 20%;
  max-height: $percentage;
}

#editor {
  width: $percentage;
  background-color: white;
  resize: none;
  color: #495057;
  border: 1px solid #ced4da;
  border-radius: 0.25rem;
  overflow-y: $car;
  max-height: $percentage;
  min-height: 40px;
  margin-bottom: 40px;
}

#preview {
  width: 98.9%;
  background-color: white;
  border-radius: 0.25rem;
  border: 1px solid #ced4da;
  overflow-y: $car;
  max-height: $percentage;
  min-height: 40px;
  margin-bottom: 40px;
}

#item1,
#item2 {
  font-family: "Russo One" !important;
  font-style: oblique !important;
  font-weight: 700 !important;
  font-size: 2em !important;
  margin-bottom: 10px;
  padding-bottom: 0px;
  width: $percentage;
  background-color: #fcf8e3;
  min-height: 50px;
  border-bottom: none;
  margin-top: 10px !important;
  padding-top: 10px !important;
}

.insignia {
  letter-spacing: 5px;
  -webkit-transition: letter-spacing 1s;
  transition: letter-spacing 1s;
}

.insignia:hover {
  letter-spacing: 13px;
  cursor: pointer;
}

.ui-resizable-s {
  cursor: row-resize;
}

textarea:focus,
input:focus {
  outline: none;
}

#arrow {
  background-color: #dff0d8;
  width: $percentage;
  height: 15px;
  position: $position;
  bottom: -12px;
  padding-left: 0px;
  padding-right: 0px;
  font-size: 1.5em;
  border-bottom: 1px solid #d6e9c6;
  text-align: center;
}

.glyphicon {
  top: -4px;
  left: 4px;
  color: gray;
  -ms-transform: scale(1, 0.6); /* IE 9 */
  -webkit-transform: scale(1, 0.6); /* Safari */
  transform: scale(1, 0.6);
}

#eraser {
  text-align: center;
  grid-column: 1 / 3;
  z-index: 2;
  line-height: 10px;
  margin-left: $car;
  margin-right: $car;
}

/*Additional styling*/

td,
th {
  border: 2px solid #224b4b;
  padding-left: 5px;
  padding-right: 5px;
}

.label {
  position: $position;
  top: -10px;
  left: 0px;
  min-width: $percentage;
  z-index: 999;
}

.preview-editor {
  position: fixed;
  top: 55px;
  left: 0px;
  min-width: $percentage;
  height: $percentage;
  z-index: 999;
}

h1 {
  margin-top: 10px !important;
  padding-top: 10px !important;
  border-bottom: 2px solid #224b4b;
}

h2 {
  border-bottom: 1px solid #224b4b;
}

code {
  background-color: #d6e9c6;
  color: #e83e8c !important;
}

blockquote {
  border-left: 2px solid black;
  padding-left: 5px;
  margin-left: 25px;
}

@media only screen and (max-width: 768px) {
  img {
    width: 100%;
  }

  #ggED {
    text-align: left;
  }

  #ggPrev {
    text-align: right;
  }

  .insignia,
  .insignia:hover {
    letter-spacing: 0px !important;
    font-size: 1em !important;
  }

  #root {
    //font-size: 1.25em;
  }
}

JS part:

/*const Inner2 = (props) => {
    return (
            <div id={this.props.id} className={this.props.className} style={this.props.style} onDoubleClick={this.props.onDoubleClick}>Editor:</div>
        );  
};*/

var renderer = new marked.Renderer();
renderer.link = function(href, title, text) {
  return (
    '<a target="_blank" href="' +
    href +
    '" title="' +
    title +
    '">' +
    text +
    "</a>"
  );
};

marked.setOptions({
  breaks: true,
  renderer: renderer,
  sanitize: true
});

class DisplayMessages extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      markdown: defaultMarkdown,
      erase: false,
      goFull: false,
      headViewKlasa: "grid-item",
      headEdKlasa: "grid-item",
      editorKlasa: "",
      previewKlasa: "",
      stilPreview: {},
      stilEditor: {},
      attr: "Click on me for fullscreen",
      inner2H: "",
      h2Inner: false
    };
    this.handleChange = this.handleChange.bind(this);
    this.eraseFields = this.eraseFields.bind(this);
    this.inner2Height = this.inner2Height.bind(this);
  }

  eraseFields() {
    this.setState({
      erase: true
    });

    if (this.state.erase === false) {
      this.setState({
        markdown: ""
      });
    }

    if (this.state.erase === true) {
      this.setState({
        markdown: defaultMarkdown,
        erase: !this.state.erase
      });
    }
  }

  /*componentDidMount() {
    this.node = ReactDOM.findDOMNode(this);
    $(this.node).resizable({
      handles: "s",
      minHeight: 170
    });

    document
      .querySelector(".ui-resizable-handle.ui-resizable-s")
      .setAttribute(
        "title",
        "Double click on me or pull me down to full height"
      );
  }*/

  inner2Height() {
    if (this.state.h2Inner === false) {
      this.setState({
        inner2H: "100%",
        h2Inner: true
      });
    }

    if (this.state.h2Inner === true) {
      this.setState({
        inner2H: "",
        h2Inner: false
      });
    }
  }

  fullScreen(clicked_id) {
    if (clicked_id === "ggEd" && this.state.goFull === false) {
      this.setState({
        headEdKlasa: this.state.headEdKlasa + " label",
        attr: "Click again to go back!",
        editorKlasa: "preview-editor",
        stilPreview: { display: "none" },
        stilEditor: { paddingTop: "0px" },
        goFull: true
      });
    }

    if (clicked_id === "ggEd" && this.state.goFull === true) {
      this.setState({
        headEdKlasa: this.state.headEdKlasa.substr(0, 9),
        attr: "Click on me for fullscreen",
        editorKlasa: "",
        stilPreview: { display: "block" },
        stilEditor: { paddingTop: "10px" },
        goFull: !this.state.goFull
      });
    }

    if (clicked_id === "ggPrev" && this.state.goFull === false) {
      this.setState({
        headViewKlasa: this.state.headViewKlasa + " label",
        attr: "Click again to go back!",
        previewKlasa: "preview-editor",
        stilEditor: { display: "none" },
        stilPreview: { paddingTop: "0px" },
        goFull: true
      });
    }

    if (clicked_id === "ggPrev" && this.state.goFull === true) {
      this.setState({
        headViewKlasa: this.state.headViewKlasa.substr(0, 9),
        attr: "Click on me for fullscreen",
        previewKlasa: "",
        stilEditor: { display: "block" },
        stilPreview: { paddingTop: "10px" },
        goFull: !this.state.goFull
      });
    }
  }

  handleChange(event) {
    this.setState({
      markdown: event.target.value
    });
  }

  render() {
    const btnText = this.state.erase ? "Populate" : "Erase";
    const handleClick = e => this.fullScreen(e.target.id);
    return (
      <div
        id="inner2"
        className="grid-container animated zoomIn"
        style={{ height: this.state.inner2H }}
        onDoubleClick={this.inner2Height}
      >
        <EditorHead
          id={"item1"}
          style={this.state.stilEditor}
          className={this.state.headEdKlasa}
          onClick={handleClick}
          title={this.state.attr}
        />

        <PreviewHead
          id={"item2"}
          style={this.state.stilPreview}
          className={this.state.headViewKlasa}
          onClick={handleClick}
          title={this.state.attr}
        />

        <BtnEraser
          id={"eraser"}
          onClick={this.eraseFields}
          type={"button"}
          className={"btn btn-danger btn-lg"}
          title={"Erase & populate both fields"}
          value={btnText}
        />

        <Editor
          id={"editor"}
          onChange={this.handleChange}
          className={this.state.editorKlasa}
          value={this.state.markdown}
          placeholder={"Enter ... some kind a text!? ..."}
          title={
            "This is rather obvious isn't it? It's editor window Sherlock :D"
          }
        />

        <Preview
          id={"preview"}
          className={this.state.previewKlasa}
          dangerouslySetInnerHTML={{
            __html: marked(this.state.markdown, { renderer: renderer })
          }}
          title={"It's a preview window, Sherlock ;)"}
        />

        <Arrow id={"arrow"} />
      </div>
    );
  }
}

/*class Inner2 extends React.Component{

    render(){ 
        return (
            <div id={this.props.id} className={this.props.className} style={this.props.style} onDoubleClick={this.props.onDoubleClick}>Editor:</div>
        );  
    }
}*/

class EditorHead extends React.Component {
  render() {
    return (
      <h1
        id={this.props.id}
        style={this.props.style}
        className={this.props.className}
        onClick={this.props.onClick}
      >
        <span className="insignia" title={this.props.title} id="ggEd">
          Editor:
        </span>
      </h1>
    );
  }
}

class PreviewHead extends React.Component {
  render() {
    return (
      <h1
        id={this.props.id}
        style={this.props.style}
        className={this.props.className}
        onClick={this.props.onClick}
      >
        <span className="insignia" title={this.props.title} id="ggPrev">
          Previewer:
        </span>
      </h1>
    );
  }
}

class BtnEraser extends React.Component {
  render() {
    return (
      <button
        id={this.props.id}
        onClick={this.props.onClick}
        type={this.props.type}
        className={this.props.className}
        title={this.props.title}
      >
        {this.props.value}
      </button>
    );
  }
}

class Editor extends React.Component {
  render() {
    return (
      <textarea
        id={this.props.id}
        onChange={this.props.onChange}
        className={this.props.className}
        value={this.props.value}
        placeholder={this.props.placeholder}
        title={this.props.title}
      />
    );
  }
}

class Preview extends React.Component {
  render() {
    return (
      <div
        id={this.props.id}
        className={this.props.className}
        dangerouslySetInnerHTML={this.props.dangerouslySetInnerHTML}
        title={this.props.title}
      />
    );
  }
}

class Arrow extends React.Component {
  render() {
    return (
      <div id={this.props.id}>
        <Glyph className={"glyphicon glyphicon-align-justify"} />
      </div>
    );
  }
}

class Glyph extends React.Component {
  render() {
    return <span className={this.props.className} />;
  }
}

ReactDOM.render(<DisplayMessages />, document.getElementById("root"));

Codepen

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.