harunpehlivan
3/6/2018 - 11:02 PM

FCC Markdown Viewer

FCC Markdown Viewer

<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
// *************  reset css *************
html, body, ul, ol, li, form, fieldset, legend {
  margin  : 0;
  padding : 0;
  }

h1, h2, h3, h4, h5, h6, p { margin-top : 0; }

fieldset, img { border : 0; }

li { list-style : none; }

// ************* variables css *************
$body-bg-color : #d6d6d6;
$navbar-bg-color : #000000;
$navbar-border-bottom : #008000;
$static-h1-color : #4F636F;
$designed-using-color : #6b6649;
$markdown-bg-color : #bee0cc;
$markdown-text-color : #00008B;

// *************  main document styling css *************
body {
  box-sizing       : border-box;
  background-color : $body-bg-color;
  font-family      : 'Ek Mukta', sans-serif;
  height           : 100%;
  padding-top      : 140px;
  display          : flex !important;
  #root.container {
    display    : flex !important;
    text-align : center;
    font-size  : 16px;
    margin     : 0 auto;
    height: 100%;
    .navbar {
      background    : $navbar-bg-color;
      padding       : 4px;
      transition    : all .5s ease-out;
      border-bottom : 10px solid $navbar-border-bottom;
      margin-bottom : 100px;
      .navbar-brand {
        margin    : 4px 0 0 0;
        font-size : 1.4em;
        }
      // -- end navbar-brand --
      .navbar-collapse ul {
        padding-top  : 4px;
        margin-right : 40px;
        float        : right;
        }
      // -- end navbar-collapse ul --
      img {
        margin-top : 8px;
        padding    : 0 30px 0 40px;
        }
      // -- end img --
      }
    // -- end navbar --
    #app-render-return-wrapper {
      margin : 0 auto;
      #page-content-wrapper {
        margin : 0 auto;
        #center-main {
          margin : 0 auto;
          #static-h1 {
            text-align  : center;
            font-size   : 2.6em;
            font-weight : 400;
            color       : $static-h1-color;
            text-shadow : 1px 1px 1px rgb(21, 22, 29);
            }
          // -- end static-h1 --
          h3 {
            font-size : 1.4em;
            }
          h4 {
            font-style : italic;
            }
          #designed-using-text {
            color : $designed-using-color;
            }
          // -- end designed-using-text --
          #markdown-viewer {
            margin    : 0 auto;
            height    : auto;
            display   : flex;
            flex-wrap : wrap;
            flex      : 1 0 auto;
            .work-area {
              height  : 400px;
              width   : 460px;
              padding : 10px;
              display : flex;
              }
            // -- end work-area --
            #markdown {
              background-color : $markdown-bg-color;
              border           : solid 1px black;
              margin           : 30px 15px 30px 0;
              resize           : none;
              color            : $markdown-text-color;
              font-size        : 0.9em;
              float            : left;
              }
            // -- end markdown --
            #viewer-outside {
              background-color : $markdown-bg-color;
              margin           : 30px 0 30px 15px;
              border           : 1px solid #444444;
              overflow         : auto;
              float            : right;
              #viewer-inside {
                color      : $markdown-text-color;
                text-align : left;
                font-size  : 0.8em;
                padding    : 0 !Important;
                margin     : 0 !Important;
                }
              // -- end viewer-inside --
              }
            // -- end viewer-outside --
            }
          // -- end markdown viewer --
          }
        // -- end center-main --
        }
      // -- end page-content-wrapper --
      }
    // -- app-render-return-wrapper --
    }
  // -- end root (React Mounting Point) --
  }

// -- end body --

// *************  Media Queries css *************
@media all and (max-width : 1200px) {
  #markdown {
    margin : 30px 10px 30px 0 !important;
    }

  #viewer-outside {
    margin : 30px 0 30px 10px !important;
    }
  }

@media all and (max-width : 991px) {
  body {
    padding-top : 124px !important;
    }

  .navbar-header {
    float : none !important;
    }

  .navbar-toggle {
    display : block !important;
    }

  .navbar-fixed-top {
    top          : 0 !important;
    border-width : 0 0 1px !important;
    }
  .navbar-collapse.collapse {
    display : none !important;
    }

  .collapse.in {
    display : block !important;
    }

  .work-area {
    height : 260px !important;
    }

  #markdown {
    margin : 20px auto 10px auto !important;
    }
  #viewer-outside {
    margin : 10px auto 20px auto !important;
    }
  }

@media all and (max-width : 768px) {
  body {
    padding-top : 100px !important;
    }
  .navbar-brand {
    font-size : 1.3em !important;
    }
  .navbar img {
    padding : 0 0 0 30px !important;
    }
  #static-h1 {
    font-size : 2.0em !important;
    }
  #center-main h3 {
    font-size : 1.2em !important;
    }
  #center-main h4 {
    font-size : 0.9em !important;
    }
  }

@media all and (max-width : 520px) {
  #center-main h3 {
    font-size : 1.0em !important;
    }
  .work-area {
    height : 240px !important;
    width  : 340px !important;
    }
  #markdown {
    font-size : 0.8em !important;
    }
  #viewer-inside {
    font-size : 0.8em !important;
    }
  }

@media all and (max-width : 400px) {
  body {
    padding-top : 98px !important;
    }
  .container {
    padding : 3px !important;
    }
  .navbar-brand {
    font-size : 1.0em !important;
    }
  .navbar img {
    padding : 0 0 0 10px !important;
    }
  #static-h1 {
    font-size : 1.7em !important;
    }
  #center-main h4 {
    font-size : 0.8em !important;
    }
  #center-main h3 {
    font-size : 0.8em !important;
    }
  .work-area {
    height : 240px !important;
    width  : 320px !important;
    }
  #markdown {
    font-size : 0.8em !important;
    }
  #viewer-inside {
    font-size : 0.8em !important;
    }
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.6/marked.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
const Header = () => {
    return (
        <nav className="navbar navbar-inverse navbar-fixed-top" role="navigation">
            <div className="container-fluid">
                {/* Brand and toggle get grouped for better mobile display */}
                <div className="navbar-header">
                    <button type="button" className="navbar-toggle collapsed" data-toggle="collapse"
                            data-target="#bs-example-navbar-collapse-1">
                        <span className="sr-only">Toggle navigation</span>
                        <span className="icon-bar"></span>
                        <span className="icon-bar"></span>
                        <span className="icon-bar"></span>
                    </button>
                    <a href="#" className="navbar-left pull-left"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/368633/react_sass_logo.jpg" alt="React Sass Logo"/></a>
                    <a className="navbar-brand" href="https://www.freecodecamp.com/" target="_blank">Free Code
                        Camp</a>
                </div> {/* .navbar-header */}
                {/* Collect the nav links and other content for toggling */}
                <div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul className="nav navbar-nav">
                        <li>
                            <a href="https://www.freecodecamp.com/challenges/build-a-markdown-previewer"
                               target="_blank">Assignment Requirements</a>
                        </li>
                        <li>
                            <a href="https://guides.github.com/features/mastering-markdown/" target="_blank">GitHub
                                Guide to Markdown</a>
                        </li>
                        <li>
                            <a href="https://codepen.io/RickStewart/pens/public/" target="_blank">My Codepens</a>
                        </li>
                    </ul>
                </div> {/* .collapse navbar-collapse */}
            </div>
        </nav>
    )
}

const PageContent = (props) => {
    return (
        <div id="page-content-wrapper">
            <div id="center-main">
                <h1 id="static-h1">Markdown Viewer</h1>
                <h3>Write Github flavored markdown and see a live preview</h3>
                <h4 id="designed-using-text">Designed using React and Sass</h4>
                <InputOutputPanels markdown={props.markdown} handleChange={props.handleChange}/>
            </div>
        </div>
    )
}

const InputOutputPanels = (props) => {
    return (
        <div id="markdown-viewer">
            <MarkdownWindow markdown={props.markdown} handleChange={props.handleChange}/>
            <PreviewWindow markdown={props.markdown}/>
        </div>
    )
}

const MarkdownWindow = (props) => {
    return (
        <textarea id="markdown" className="work-area" onChange={props.handleChange}
                  value={props.markdown}></textarea>
    )
}

const markdownText = (text) => {
    return {__html: marked(text)};
}

/* You cannot render markup directly to a textarea or div - the html tags are rendered literally to the screen without being interpreted.
 * see https://facebook.github.io/react/docs/dom-elements.html and dangerouslySetInnerHTML */
const PreviewWindow = (props) => {
    let text = props.markdown;
    return (
        <div id="viewer-outside" className="work-area">
            <div id="viewer-inside" dangerouslySetInnerHTML={markdownText(text)}></div>
        </div>
    )
}

class App extends React.Component {
    constructor() {
        super();
        marked.setOptions({
            gfm: true,
            breaks: true,
            sanitize: true
        });

        this.handleChange = this.handleChange.bind(this);

        this.state = {
            markdown: "# Github Markdown!\n( Edit me )\n# h1 tag\n## h2 tag\n### h3 tag\n##### h5 tag\n##### **Bold text** and *Italics text*\n### Create Paragraphs\nThe quick brown fox jumped over the lazy dogs back. Now is the time for all good men to come to the aid of their party.\n\nThese two sentences were used for practice. The first sentence was used to practice Morse code, it uses all the letters in the English alphabet. The second sentence was used as a typing drill in the late 1800's by instructor Charles E. Weller.\n>  You can add a quote!\n\n### Make **ordered** lists:\n#### Refreshment\n    1. glass\n    2. vodka\n    3. orange juice\n\n### Make **unordered** lists:\n#### Snack\n    * Cheese\n    * Crackers\n \n### You can insert a block of code\n```javascript \nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from './App';     \n\nReactDOM.render(\n    <App />, \n    document.getElementById('root')\n);\n```\n### Two ways to reference a URL:\n[Named Link](http://www.markitdown.net/)  \nor  \n<https://guides.github.com/features/mastering-markdown/>"
        };
    }

    /* added method handleChange here because App holds the state. */
    handleChange = (event) => {
        this.setState({markdown: event.target.value});
    };

    render() {
        return (
            <div id="app-render-return-wrapper">
                <Header />
                <PageContent markdown={this.state.markdown} handleChange={this.handleChange}/>
            </div>
        );
    }
}

ReactDOM.render(
  <App />, 
  document.getElementById("root")
);
<body>
        <div id="root" class="container"></div> <!-- React Mounting-point, content managed by React DOM -->
</body>

FCC Markdown Viewer

This is a FreeCodeCamp project to build a GitHub flavored markdown editor with a live preview. The project was to be built using React and Sass.

A Pen by HARUN PEHLİVAN on CodePen.

License.