├── .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 |
29 |
30 |
35 |
36 | );
37 | }
38 | });
39 |
40 | ReactDom.render(
41 | ,
42 | document.getElementById('root')
43 | );
44 |
45 | function supportsLocalStorage() {
46 | var mod = 'test';
47 | try {
48 | localStorage.setItem(mod, mod);
49 | localStorage.removeItem(mod);
50 | return true;
51 | } catch (e) {
52 | return false;
53 | }
54 | }
55 |
56 | function getDefaultSource() {
57 | return (hasLocalStorage && localStorage.markdownSource) || [
58 | '# markdown-editor', '',
59 | 'Super simple markdown editor/previewer, based on ',
60 | '[react-markdown](https://github.com/rexxars/react-markdown)',
61 | '',
62 | '**Note: HTML input is disabled in this editor, for now**',
63 | '',
64 |
65 | '## Flow', '',
66 | '* When source in the editor is changed:',
67 | ' * Callback is triggered',
68 | ' * Updates state on app component',
69 | ' * App component sets new source on preview component (react-markdown)',
70 | ' * Changes are reflected!',
71 | '* As a bonus, a debounced method stores the editor value to localStorage (if available)',
72 | '',
73 |
74 | '## License', '',
75 | '* MIT-licensed'
76 | ].join('\n');
77 | }
78 |
--------------------------------------------------------------------------------