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\$
0

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.