├── .eslintignore ├── dist ├── .gitkeep ├── bg.png ├── index.html ├── editor.css └── pure.css ├── .babelrc ├── .eslintrc ├── .gitignore ├── webpack.config.js ├── README.md ├── LICENSE ├── package.json └── app └── app.js /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /dist/.gitkeep: -------------------------------------------------------------------------------- 1 | Keep me 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "vaffel/react" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist/bundle.js.map 3 | -------------------------------------------------------------------------------- /dist/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rexxars/markdown-editor/HEAD/dist/bg.png -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Markdown editor 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | 5 | var config = { 6 | entry: path.join(__dirname, 'app', 'app.js'), 7 | output: { 8 | path: path.join(__dirname, 'dist'), 9 | filename: 'bundle.js' 10 | }, 11 | module: { 12 | loaders: [ 13 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'}, 14 | { test: /\.json$/, loader: 'json-loader' } 15 | ] 16 | } 17 | }; 18 | 19 | if (process.env.NODE_ENV !== 'production') { 20 | config.cache = true; 21 | config.devtool = 'source-map'; 22 | } 23 | 24 | module.exports = config; 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # markdown-editor 2 | 3 | Super-simple markdown editor with live preview, using [react-markdown](https://github.com/rexxars/react-markdown), in ~50 lines of code. 4 | 5 | ## Running 6 | 7 | See the online demo at http://rexxars.github.io/markdown-editor/, or if you want to run it locally: 8 | 9 | ```bash 10 | git clone https://github.com/rexxars/markdown-editor.git 11 | cd markdown-editor 12 | npm install 13 | npm run dev 14 | 15 | # Point your browser to http://localhost:7799/ 16 | ``` 17 | 18 | ## Notes 19 | 20 | This isn't meant to be a fully-featured Markdown editor. For that, check out [Dillinger.io](http://dillinger.io/). This is primarily meant to be a simple example of how you can use [react-markdown](https://github.com/rexxars/react-markdown). 21 | 22 | ## License 23 | 24 | MIT-licensed. See LICENSE. 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Espen Hovlandsdal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dist/editor.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-box-sizing: border-box; 3 | -moz-box-sizing: border-box; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | background: url(bg.png); 9 | } 10 | 11 | html, body { 12 | height: 100%; 13 | width: 100%; 14 | padding: 0; 15 | margin: 0; 16 | } 17 | 18 | .editor { 19 | position: fixed; 20 | top: 0; 21 | left: 0; 22 | height: 100%; 23 | padding: 1em; 24 | font-family: 'Roboto Mono', monospace; 25 | border: 0; 26 | border-right: 1px solid rgb(169, 169, 169); 27 | resize: none; 28 | } 29 | 30 | .preview { 31 | margin-left: 50%; 32 | min-height: 100%; 33 | padding: 0 1em; 34 | font: Helvetica, Arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 35 | color: #333; 36 | } 37 | 38 | .editor, .preview { 39 | width: 50%; 40 | } 41 | 42 | .preview code[class^="language-"] { 43 | display: block; 44 | background: #f8f8f8; 45 | padding: 0.5em; 46 | overflow-x: auto; 47 | } 48 | 49 | .preview blockquote { 50 | margin: 0; 51 | padding-left: 1.5em; 52 | border-left: 0.5em #ccc solid; 53 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "markdown-editor", 3 | "version": "1.0.0", 4 | "description": "Simple markdown editor with live preview, using react-markdown", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "eslint .", 8 | "dev": "webpack-dev-server --content-base dist/ --port 7799", 9 | "build": "NODE_ENV=production webpack -p" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+ssh://git@github.com/rexxars/markdown-editor.git" 14 | }, 15 | "keywords": [ 16 | "markdown", 17 | "editor", 18 | "preview", 19 | "react" 20 | ], 21 | "author": "Espen Hovlandsdal ", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/rexxars/markdown-editor/issues" 25 | }, 26 | "homepage": "https://github.com/rexxars/markdown-editor#readme", 27 | "devDependencies": { 28 | "babel-core": "^6.5.2", 29 | "babel-loader": "^6.2.3", 30 | "babel-preset-react": "^6.3.13", 31 | "eslint": "^1.10.3", 32 | "eslint-config-vaffel": "^3.0.0", 33 | "eslint-plugin-react": "^3.13.1", 34 | "json-loader": "^0.5.4", 35 | "webpack": "^1.12.9", 36 | "webpack-dev-server": "^1.14.0" 37 | }, 38 | "dependencies": { 39 | "lodash.debounce": "^3.1.1", 40 | "react": "^15.0.1", 41 | "react-dom": "^15.0.1", 42 | "react-markdown": "^2.0.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /dist/pure.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.6.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yahoo/pure/blob/master/LICENSE.md 6 | */ 7 | /*! 8 | normalize.css v^3.0 | MIT License | git.io/normalize 9 | Copyright (c) Nicolas Gallagher and Jonathan Neal 10 | */ 11 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block} 12 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react'); 4 | var ReactDom = require('react-dom'); 5 | var debounce = require('lodash.debounce'); 6 | var Markdown = require('react-markdown'); 7 | 8 | var hasLocalStorage = supportsLocalStorage(); 9 | var initialSource = getDefaultSource(); 10 | 11 | var App = React.createClass({ 12 | onChange: function(e) { 13 | this.setState({ source: e.target.value }); 14 | this.storeSource(e.target.value); 15 | }, 16 | 17 | storeSource: hasLocalStorage ? debounce(function(src) { 18 | localStorage.markdownSource = src || initialSource; 19 | }, 250) : function() {}, 20 | 21 | render: function() { 22 | return ( 23 |
24 |