Created
September 13, 2020 08:07
-
-
Save walemust/a87534d75038d0b33c4f2d37c1470db9 to your computer and use it in GitHub Desktop.
Fork Me! FCC: Markdown Previewer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#app |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const projectName = "markdown-previewer"; | |
localStorage.setItem('example_project', 'Markdown Previewer'); | |
// ALLOWS LINE BREAKS WITH RETURN BUTTON | |
marked.setOptions({ | |
breaks: true, | |
}); | |
// INSERTS target="_blank" INTO HREF TAGS (required for codepen links) | |
const renderer = new marked.Renderer(); | |
renderer.link = function (href, title, text) { | |
return `<a target="_blank" href="${href}">${text}` + '</a>'; | |
} | |
class App extends React.Component{ | |
constructor(props) { | |
super(props); | |
this.state = { | |
markdown: placeholder, | |
editorMaximized: false, | |
previewMaximized: false | |
} | |
this.handleChange = this.handleChange.bind(this); | |
this.handleEditorMaximize = this.handleEditorMaximize.bind(this); | |
this.handlePreviewMaximize = this.handlePreviewMaximize.bind(this); | |
} | |
handleChange(e) { | |
this.setState({ | |
markdown: e.target.value | |
}); | |
} | |
handleEditorMaximize() { | |
this.setState({ | |
editorMaximized: !this.state.editorMaximized | |
}); | |
} | |
handlePreviewMaximize() { | |
this.setState({ | |
previewMaximized: !this.state.previewMaximized | |
}); | |
} | |
render() { | |
const classes = this.state.editorMaximized ? | |
['editorWrap maximized', | |
'previewWrap hide', | |
'fa fa-compress'] : | |
this.state.previewMaximized ? | |
['editorWrap hide', | |
'previewWrap maximized', | |
'fa fa-compress'] : | |
['editorWrap', | |
'previewWrap', | |
'fa fa-arrows-alt']; | |
return ( | |
<div> | |
<div className={classes[0]}> | |
<Toolbar | |
icon={classes[2]} | |
onClick={this.handleEditorMaximize} | |
text="Editor"/> | |
<Editor markdown={this.state.markdown} | |
onChange={this.handleChange} /> | |
</div> | |
<div className="converter"> | |
</div> | |
<div className={classes[1]}> | |
<Toolbar | |
icon={classes[2]} | |
onClick={this.handlePreviewMaximize} | |
text="Previewer"/> | |
<Preview markdown={this.state.markdown}/> | |
</div> | |
</div> | |
) | |
} | |
}; | |
const Toolbar = (props) => { | |
return ( | |
<div className="toolbar"> | |
<i title="no-stack-dub-sack" className="fa fa-free-code-camp"/> | |
{props.text} | |
<i onClick={props.onClick} className={props.icon}></i> | |
</div> | |
) | |
} | |
const Editor = (props) => { | |
return ( | |
<textarea id="editor" | |
value={props.markdown} | |
onChange={props.onChange} | |
type="text"/> | |
) | |
} | |
const Preview = (props) => { | |
return ( | |
<div id='preview' dangerouslySetInnerHTML={{__html: marked(props.markdown, { renderer: renderer })}} /> | |
) | |
} | |
const placeholder = | |
`# Welcome to my React Markdown Previewer! | |
## This is a sub-heading... | |
### And here's some other cool stuff: | |
Heres some code, \`<div></div>\`, between 2 backticks. | |
\`\`\` | |
// this is multi-line code: | |
function anotherExample(firstLine, lastLine) { | |
if (firstLine == '\`\`\`' && lastLine == '\`\`\`') { | |
return multiLineCode; | |
} | |
} | |
\`\`\` | |
You can also make text **bold**... whoa! | |
Or _italic_. | |
Or... wait for it... **_both!_** | |
And feel free to go crazy ~~crossing stuff out~~. | |
There's also [links](https://www.freecodecamp.com), and | |
> Block Quotes! | |
And if you want to get really crazy, even tables: | |
Wild Header | Crazy Header | Another Header? | |
------------ | ------------- | ------------- | |
Your content can | be here, and it | can be here.... | |
And here. | Okay. | I think we get it. | |
- And of course there are lists. | |
- Some are bulleted. | |
- With different indentation levels. | |
- That look like this. | |
1. And there are numbererd lists too. | |
1. Use just 1s if you want! | |
1. But the list goes on... | |
- Even if you use dashes or asterisks. | |
* And last but not least, let's not forget embedded images: | |
 | |
` | |
ReactDOM.render(<App />, document.getElementById('app')); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js"></script> | |
<script src="https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js"></script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import url('https://fonts.googleapis.com/css?family=Russo+One'); | |
$darkAccent: #224B4B; | |
$lightAccent: #2CDA9D; | |
$backgroundBase: #619E9E; | |
$shadow: 1px 1px 10px 2px darken($backgroundBase, 20%); | |
$default-border: 1px solid darken($backgroundBase, 35%); | |
body { | |
background: lighten($backgroundBase, 12%); | |
margin: 10px 0; | |
} | |
#preview, | |
.title { | |
display: inline-block; | |
} | |
.colorScheme { | |
background-color: lighten($backgroundBase, 30%); | |
border: $default-border; | |
box-shadow: $shadow; | |
border-top: none; | |
} | |
.toolbar { | |
position: relative; | |
background-color: lighten($darkAccent, 25%); | |
padding: 4px 4px 3px 3px; | |
border: $default-border; | |
box-shadow: $shadow; | |
font-family: Russo One; | |
font-size: 15px; | |
i { | |
width: 25px; | |
color: black; | |
margin-left: 5px; | |
} | |
.fa-arrows-alt, | |
.fa-compress { | |
position: absolute; | |
right: -5px; | |
} | |
} | |
.fa-retweet, | |
.fa-compress, | |
.fa-arrows-alt { | |
&:hover { | |
color: lighten($lightAccent, 10%); | |
cursor: pointer; | |
} | |
} | |
.fa-free-code-camp { | |
margin-right: 3px; | |
} | |
.editorWrap { | |
width: 600px; | |
margin: 18px auto; | |
.toolbar { | |
width: 99%; | |
} | |
textarea { | |
@extend .colorScheme; | |
width: 99%; | |
min-height: 200px; | |
margin-bottom: -5px; | |
resize: vertical; | |
outline: none; | |
padding-left: 5px; | |
padding-top: 5px; | |
font-size: 12px; | |
} | |
} | |
.converter { | |
width: 100px; | |
text-align: center; | |
font-size: 35px; | |
margin: auto; | |
} | |
.previewWrap { | |
@extend .colorScheme; | |
width: 800px; | |
margin: 20px auto; | |
min-height: 200px; | |
overflow-wrap: break-word; | |
padding-right: 20px; | |
.toolbar { | |
left: -1px; | |
width: 100%; | |
padding-right: 17px; | |
} | |
#preview { | |
margin-left: 5px; | |
margin-top: -10px; | |
width: 100%; | |
} | |
} | |
@media screen and (max-width: 850px) { | |
.previewWrap { | |
width: 630px; | |
} | |
.editorWrap { | |
width: 550px; | |
} | |
} | |
.maximized { | |
width: 96%; | |
min-height: 100vh; | |
margin: auto; | |
textarea { | |
min-height: 95vh; | |
resize: none; | |
} | |
} | |
.hide { | |
display: none; | |
} | |
@media screen and (max-width: 650px) { | |
body { | |
margin: 5px 0; | |
} | |
.editorWrap { | |
width: 80vw; | |
margin: 0 auto; | |
} | |
.maximized { | |
width: 95%; | |
margin: auto; | |
} | |
.previewWrap { | |
width: 95vw; | |
#preview { | |
width: 100%; | |
img { | |
height: 200px; | |
} | |
} | |
} | |
} | |
// MARKDOWN STYLES | |
#preview { | |
blockquote { | |
border-left: 3px solid #224B4B; | |
color: #224B4B; | |
padding-left: 5px; | |
margin-left: 25px; | |
} | |
code { | |
background: white; | |
padding: 1px 4px 2px 4px; | |
font-size: 12px; | |
font-weight: bold; | |
} | |
pre { | |
background: white; | |
padding: 5px 0 5px 5px; | |
} | |
h1 { | |
border-bottom: 2px solid $darkAccent; | |
} | |
h2 { | |
border-bottom: 1px solid $darkAccent; | |
} | |
table { | |
border-collapse: collapse; | |
} | |
td, | |
th { | |
border: 2px solid $darkAccent; | |
padding-left: 5px; | |
padding-right: 5px; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" /> | |
<link href="https://cdnjs.cloudflare.com/ajax/libs/mocha/3.0.2/mocha.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment