├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── LICENSE
├── README.md
├── asserts
├── antd-custom.less
├── editor-markedown.less
└── styles.less
├── components
├── Edit
│ ├── SimpleMde.js
│ └── index.js
├── ErrorPage.js
├── Header.js
├── Home
│ └── index.js
├── Layout.js
├── Normal
│ ├── SimpleMde.js
│ └── index.js
└── Preview
│ └── index.js
├── constants
├── ActionTypes.js
├── ApiUrlForBE.js
├── ConstTypes.js
└── CustomTheme.js
├── containers
├── home
│ └── counter.js
└── user
│ └── UserList.js
├── core
├── nextFetch.js
└── util.js
├── middlewares
├── client
│ └── user.js
└── server
│ └── README.md
├── next.config.js
├── out
├── _next
│ └── static
│ │ ├── NSy5qE4UvMw4dCrM10co1
│ │ └── pages
│ │ │ ├── _app.js
│ │ │ ├── _error.js
│ │ │ ├── edit.js
│ │ │ ├── index.js
│ │ │ ├── normal.js
│ │ │ └── preview.js
│ │ ├── chunks
│ │ ├── 0.js
│ │ ├── 1.js
│ │ ├── 10.08b5d53e0813005250ac.js
│ │ ├── 11.0b2141b385e7370d7db6.js
│ │ ├── 2.js
│ │ ├── commons.1f8d74ed5ebdd5c01cf6.js
│ │ ├── styles.c57e4bb0e5d39697731a.js
│ │ └── styles.js
│ │ ├── css
│ │ ├── commons.7a17fd1f.chunk.css
│ │ ├── commons.7a17fd1f.chunk.css.map
│ │ ├── styles.1c350e82.chunk.css
│ │ ├── styles.1c350e82.chunk.css.map
│ │ └── styles.chunk.css
│ │ ├── development
│ │ ├── dll
│ │ │ └── dll_5456783f4b96fc9b3e3a.js
│ │ └── pages
│ │ │ ├── _app.js
│ │ │ ├── _error.js
│ │ │ ├── index.js
│ │ │ └── preview.js
│ │ ├── runtime
│ │ ├── main-9d9b5feb884c2ff45459.js
│ │ ├── main.js
│ │ ├── webpack-b71bd49ef0ed4f12a8c1.js
│ │ └── webpack.js
│ │ └── webpack
│ │ ├── 052c5077de3094569559.hot-update.json
│ │ ├── 0f8744ee697c70dab960.hot-update.json
│ │ ├── 1516d8ccf198cea54b10.hot-update.json
│ │ ├── 6a1fe21aaf5cb4fe529a.hot-update.json
│ │ ├── 70577301787b6e0e7497.hot-update.json
│ │ ├── 74eb4dbfc4d60836b3a8.hot-update.json
│ │ ├── 7db70758f5c5c4335604.hot-update.json
│ │ ├── e5d126e4670caddb4c2f.hot-update.json
│ │ ├── e9002a3ce1f2ce304d4e.hot-update.json
│ │ ├── static
│ │ └── development
│ │ │ └── pages
│ │ │ ├── normal.js.0f8744ee697c70dab960.hot-update.js
│ │ │ └── normal.js.e5d126e4670caddb4c2f.hot-update.js
│ │ ├── styles.6a1fe21aaf5cb4fe529a.hot-update.js
│ │ ├── styles.70577301787b6e0e7497.hot-update.js
│ │ └── styles.74eb4dbfc4d60836b3a8.hot-update.js
├── edit
│ └── index.html
├── index.html
├── normal
│ └── index.html
├── preview
│ └── index.html
└── static
│ ├── empty.png
│ ├── favicon.ico
│ ├── logo.png
│ ├── tags
│ ├── Algorithm.png
│ ├── Angular.png
│ ├── Back.png
│ ├── CSS.png
│ ├── Database.png
│ ├── HTML.png
│ ├── Http.png
│ ├── Java.png
│ ├── JavaScript.png
│ ├── Nodejs.png
│ ├── Product.png
│ ├── Python.png
│ ├── React.png
│ ├── Vue.png
│ ├── WEB.png
│ └── Webpack.png
│ ├── unknown_error.png
│ └── users.json
├── package.json
├── pages
├── _app.js
├── _document.js
├── _error.js
├── edit
│ └── index.js
├── index.js
├── normal
│ └── index.js
└── preview
│ └── index.js
├── redux
├── actions
│ ├── home.js
│ └── user.js
├── reducers
│ ├── home
│ │ ├── counter.js
│ │ └── index.js
│ ├── index.js
│ └── user
│ │ ├── index.js
│ │ └── list.js
├── sagas
│ ├── index.js
│ └── user
│ │ ├── index.js
│ │ └── userList.js
└── store.js
├── server.js
├── static
├── empty.png
├── favicon.ico
├── logo.png
├── tags
│ ├── Algorithm.png
│ ├── Angular.png
│ ├── Back.png
│ ├── CSS.png
│ ├── Database.png
│ ├── HTML.png
│ ├── Http.png
│ ├── Java.png
│ ├── JavaScript.png
│ ├── Nodejs.png
│ ├── Product.png
│ ├── Python.png
│ ├── React.png
│ ├── Vue.png
│ ├── WEB.png
│ └── Webpack.png
├── unknown_error.png
└── users.json
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "presets": ["next/babel"],
4 | "plugins": [
5 | [
6 | "@babel/plugin-proposal-decorators",
7 | {
8 | "decoratorsBeforeExport": true
9 | }
10 | ],
11 | [
12 | "import",
13 | {
14 | "libraryName": "antd",
15 | "style": true
16 | }
17 | ],
18 | ["lodash"]
19 | ]
20 | }
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig文件使用INI格式。斜杠(/)作为路径分隔符,#或者;作为注释。路径支持通配符:
2 | # 表明是最顶层的配置文件,发现设为true时,才会停止查找.editorconfig文件
3 | root = true
4 |
5 | # * 匹配除/之外的任意字符
6 | # ** 匹配任意字符串
7 | # ? 匹配任意单个字符
8 | # [name] 匹配name字符
9 | # [!name] 不匹配name字符
10 | # [s1,s2,s3] 匹配给定的字符串
11 | # [num1..num2] 匹配num1到mun2直接的整数
12 | [*]
13 | # 文件的charset。有以下几种类型:latin1, utf-8, utf-8-bom, utf-16be, utf-16le
14 | charset = utf-8
15 | # 缩进使用 tab 或者 space
16 | indent_style = space
17 | # 缩进为 space 时,缩进的字符数
18 | indent_size = 2
19 | # 缩进为 tab 时,缩进的宽度
20 | # tab_width = 2
21 | # 换行符的类型。lf, cr, crlf三种
22 | end_of_line = lf
23 | # 是否将行尾空格自动删除
24 | trim_trailing_whitespace = true
25 | # 是否使文件以一个空白行结尾
26 | insert_final_newline = true
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .next/
3 | .editorconfig
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "parserOptions": {
4 | "ecmaVersion": 6,
5 | "sourceType": "module",
6 | "ecmaFeatures": {
7 | "jsx": true
8 | }
9 | },
10 | "env": {
11 | "es6": true,
12 | "browser": true,
13 | "node": true
14 | },
15 | "rules":{
16 | "no-console":0,
17 | "indent": [
18 | 2,
19 | 2,
20 | {
21 | "SwitchCase": 1,
22 | "ObjectExpression": 1
23 | }
24 | ],
25 | "react/jsx-uses-vars": [2],
26 | "semi": [1, "always"],
27 | "linebreak-style": 0,
28 | "consistent-return": 0,
29 | "no-use-before-define": 0,
30 | "no-multi-assign": 0,
31 | "no-lonely-if": 1,
32 | "no-nested-ternary": 0,
33 | "wrap-iife": [2, "inside"],
34 | "jsx-quotes": [2, "prefer-single"],
35 | "generator-star-spacing": 0,
36 | "react/forbid-prop-types": 0,
37 | "react/sort-comp": 1,
38 | "react/no-string-refs": 0,
39 | "react/prefer-stateless-function": 0,
40 | "react/prop-types": 2,
41 | "react/require-default-props": [2, { "forbidDefaultForRequired": true }],
42 | "jsx-a11y/no-static-element-interactions": 0,
43 | "keyword-spacing": [2, { "before": true }],
44 | "eqeqeq": [2, "always"],
45 | "space-infix-ops": [2, {"int32Hint": false}],
46 | "comma-spacing": [2, { "before": false, "after": true }],
47 | "block-spacing": 2,
48 | "no-else-return": 2
49 | },
50 | "extends": "eslint:recommended",
51 | "plugins": [
52 | "react"
53 | ]
54 | }
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # Dependencies
4 | node_modules/
5 |
6 | # Compiled output
7 | build
8 |
9 | # Runtime data
10 | database.sqlite
11 |
12 | # Test coverage
13 | coverage
14 |
15 | # Logs
16 | npm-debug.log*
17 | yarn-debug.log*
18 | yarn-error.log*
19 | logs/
20 |
21 | # Editors and IDEs
22 | .idea
23 | .vscode/*
24 | !.vscode/settings.json
25 | !.vscode/tasks.json
26 | !.vscode/launch.json
27 | !.vscode/extensions.json
28 |
29 | # Misc
30 | .DS_Store
31 |
32 | # custom
33 | .next
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 luffyZhou
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # next-markdown-editor
2 | A demo for edit & priview markdown bases on next-antd-scafflod quickly!
3 |
4 | ## Features
5 | - next.js
6 | - simplemde-markdown-editor
7 | - react-markdown
8 |
9 | ## Demo Image
10 | - home page
11 | 
12 | - normal editor
13 | 
14 | - side-by-side editor
15 | 
16 | - preview markdown
17 | 
18 |
--------------------------------------------------------------------------------
/asserts/antd-custom.less:
--------------------------------------------------------------------------------
1 | /* 系统主题颜色 */
2 | @color-primary: #52f;
3 |
4 | @primary-color: @color-primary;
5 |
6 | @layout-header-height: 40px;
7 | @border-radius-base: 2px;
8 |
--------------------------------------------------------------------------------
/asserts/editor-markedown.less:
--------------------------------------------------------------------------------
1 | /* simple-markdown-editor */
2 | .CodeMirror {
3 | width: 100% !important;
4 | top: 50px !important;
5 | bottom: 40px !important;
6 | background-color: #fafafa !important;
7 | }
8 | .editor-toolbar {
9 | display: none;
10 | }
11 | .editor-preview-side {
12 | background-color: #fff !important;
13 | bottom: 40px !important;
14 | }
15 | /* markdown css */
16 |
17 | code, pre {
18 | border-radius: 3px;
19 | background-color:#f7f7f7;
20 | color: inherit;
21 | }
22 |
23 | code {
24 | font-family: Consolas, Monaco, Andale Mono, monospace;
25 | margin: 0 2px;
26 | }
27 |
28 | pre {
29 | line-height: 1.7em;
30 | overflow: auto;
31 | padding: 6px 10px;
32 | border-left: 5px solid #6CE26C;
33 | }
34 |
35 | pre > code {
36 | border: 0;
37 | display: inline;
38 | max-width: initial;
39 | padding: 0;
40 | margin: 0;
41 | overflow: initial;
42 | line-height: inherit;
43 | font-size: .85em;
44 | white-space: pre;
45 | background: 0 0;
46 |
47 | }
48 |
49 | code {
50 | color: #666555;
51 | }
52 |
53 | aside {
54 | display: block;
55 | float: right;
56 | width: 390px;
57 | }
58 | blockquote {
59 | border-left:.5em solid #eee;
60 | padding: 0 0 0 2em;
61 | margin-left:0;
62 | }
63 | blockquote cite {
64 | font-size:14px;
65 | line-height:20px;
66 | color:#bfbfbf;
67 | }
68 | blockquote cite:before {
69 | content: '\2014 \00A0';
70 | }
71 |
72 | blockquote p {
73 | color: #666;
74 | }
75 | hr {
76 | text-align: left;
77 | color: #999;
78 | height: 2px;
79 | padding: 0;
80 | margin: 16px 0;
81 | background-color: #e7e7e7;
82 | border: 0 none;
83 | }
84 |
85 | dl {
86 | padding: 0;
87 | }
88 |
89 | dl dt {
90 | padding: 10px 0;
91 | margin-top: 16px;
92 | font-size: 1em;
93 | font-style: italic;
94 | font-weight: bold;
95 | }
96 |
97 | dl dd {
98 | padding: 0 16px;
99 | margin-bottom: 16px;
100 | }
101 |
102 | dd {
103 | margin-left: 0;
104 | }
105 | table {
106 | *border-collapse: collapse; /* IE7 and lower */
107 | border-spacing: 0;
108 | width: 100%;
109 | }
110 | table {
111 | border: solid #ccc 1px;
112 | -moz-border-radius: 6px;
113 | -webkit-border-radius: 6px;
114 | border-radius: 6px;
115 | }
116 | table tr:hover {
117 | background: #fbf8e9;
118 | -o-transition: all 0.1s ease-in-out;
119 | -webkit-transition: all 0.1s ease-in-out;
120 | -moz-transition: all 0.1s ease-in-out;
121 | -ms-transition: all 0.1s ease-in-out;
122 | transition: all 0.1s ease-in-out;
123 | }
124 | table td, .table th {
125 | border-left: 1px solid #ccc;
126 | border-top: 1px solid #ccc;
127 | padding: 10px;
128 | text-align: left;
129 | }
130 |
131 | table th {
132 | background-color: #dce9f9;
133 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebf3fc), to(#dce9f9));
134 | background-image: -webkit-linear-gradient(top, #ebf3fc, #dce9f9);
135 | background-image: -moz-linear-gradient(top, #ebf3fc, #dce9f9);
136 | background-image: -ms-linear-gradient(top, #ebf3fc, #dce9f9);
137 | background-image: -o-linear-gradient(top, #ebf3fc, #dce9f9);
138 | background-image: linear-gradient(top, #ebf3fc, #dce9f9);
139 | border-top: none;
140 | text-shadow: 0 1px 0 rgba(255,255,255,.5);
141 | padding: 5px;
142 | }
143 |
144 | table td:first-child, table th:first-child {
145 | border-left: none;
146 | }
147 |
148 | table th:first-child {
149 | -moz-border-radius: 6px 0 0 0;
150 | -webkit-border-radius: 6px 0 0 0;
151 | border-radius: 6px 0 0 0;
152 | }
153 | table th:last-child {
154 | -moz-border-radius: 0 6px 0 0;
155 | -webkit-border-radius: 0 6px 0 0;
156 | border-radius: 0 6px 0 0;
157 | }
158 | table th:only-child{
159 | -moz-border-radius: 6px 6px 0 0;
160 | -webkit-border-radius: 6px 6px 0 0;
161 | border-radius: 6px 6px 0 0;
162 | }
163 | table tr:last-child td:first-child {
164 | -moz-border-radius: 0 0 0 6px;
165 | -webkit-border-radius: 0 0 0 6px;
166 | border-radius: 0 0 0 6px;
167 | }
168 | table tr:last-child td:last-child {
169 | -moz-border-radius: 0 0 6px 0;
170 | -webkit-border-radius: 0 0 6px 0;
171 | border-radius: 0 0 6px 0;
172 | }
--------------------------------------------------------------------------------
/asserts/styles.less:
--------------------------------------------------------------------------------
1 | @import "~antd/dist/antd.less";
2 | @import "./editor-markedown.less";
3 | @import "./antd-custom.less";
4 |
--------------------------------------------------------------------------------
/components/Edit/SimpleMde.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import SimpleMDE from 'simplemde';
3 | import marked from 'marked';
4 | import hljs from 'highlight.js';
5 | import 'simplemde/dist/simplemde.min.css';
6 | import 'highlight.js/styles/github.css';
7 |
8 | class SimpleMDEditor extends Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = { };
12 | this.smde = null;
13 | }
14 |
15 | componentDidMount() {
16 | // 编辑器内容点击不弹文字
17 | document.getElementById('markdownEditor')
18 | .parentNode // 获取编辑器container
19 | .addEventListener('click', e => e.stopPropagation());
20 | this.smde = new SimpleMDE({
21 | element: document.getElementById('markdownEditor').childElementCount,
22 | autofocus: true,
23 | autosave: true,
24 | initialValue: '',
25 | indentWithTabs: false,
26 | placeholder: '## 输入试题内容...',
27 | renderingConfig: {
28 | singleLineBreaks: false,
29 | codeSyntaxHighlighting: true,
30 | },
31 | insertTexts: {
32 | horizontalRule: ["", "\n\n-----\n\n"],
33 | image: [""],
34 | link: ["[", "](http://)"],
35 | table: ["", "\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n"],
36 | },
37 | previewRender: function(plainText) {
38 | return marked(plainText, {
39 | renderer: new marked.Renderer(),
40 | gfm: true,
41 | pedantic: false,
42 | sanitize: false,
43 | tables: true,
44 | breaks: true,
45 | smartLists: true,
46 | smartypants: true,
47 | highlight: function (code) {
48 | return hljs.highlightAuto(code).value;
49 | }
50 | });
51 | },
52 | spellChecker: false
53 | });
54 | SimpleMDE.toggleSideBySide(this.smde);
55 | }
56 |
57 | render() {
58 | return (
59 |
60 |
61 |
62 | );
63 | }
64 | }
65 |
66 | export default SimpleMDEditor;
--------------------------------------------------------------------------------
/components/Edit/index.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import dynamic from 'next/dynamic';
3 | import { Input } from 'antd';
4 |
5 | const SimpleMDEditor = dynamic(import('./SimpleMde'), {
6 | ssr: false
7 | });
8 |
9 | class Edit extends Component {
10 |
11 | constructor(props) {
12 | super(props);
13 | this.state = { };
14 | }
15 |
16 | render() {
17 | return (
18 |
19 |
58 |
62 |
67 |
68 | 编辑页面底部内容
69 |
70 |
71 | );
72 | }
73 | }
74 |
75 | export default Edit;
--------------------------------------------------------------------------------
/components/ErrorPage.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Button } from 'antd';
4 | import Router from 'next/router';
5 |
6 | class ErrorPage extends Component {
7 | static propTypes = {
8 | statusCode: PropTypes.number.isRequired
9 | }
10 | render() {
11 | let RenderComp;
12 | switch (this.props.statusCode) {
13 | case 200:
14 | case 404: {
15 | RenderComp = () => (
16 |
17 |
34 |

35 |
您访问的页面不存在,请确认地址准确~
36 |
37 |
38 | );
39 | break;
40 | }
41 | case 500: {
42 | RenderComp = () => (
43 |
44 |
61 |

62 |
您访问的页面出现未知错误,程序员小哥正在加紧修复~
63 |
64 |
65 | );
66 | break;
67 | }
68 | default:
69 | break;
70 | }
71 | return (
72 |
73 | );
74 | }
75 | }
76 |
77 | export default ErrorPage;
--------------------------------------------------------------------------------
/components/Header.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Link from 'next/link';
4 | import { color_primary } from '../constants/CustomTheme';
5 |
6 | class Header extends Component {
7 | static propTypes = {
8 | title: PropTypes.string
9 | }
10 | static defaultProps = {
11 | title: ''
12 | }
13 | constructor(props) {
14 | super(props);
15 | const { title } = props;
16 | this.state = { title };
17 | }
18 |
19 | static getDerivedStateFromProps(nextProps, prevState) {
20 | if (nextProps.title !== prevState.title) {
21 | return {
22 | title: nextProps.title
23 | };
24 | }
25 | return null;
26 | }
27 |
28 | render() {
29 | const { title } = this.state;
30 | return (
31 |
32 |
69 |
70 |
71 |

72 |
XXX系统
73 |
74 |
75 |
{title}
76 |
77 | );
78 | }
79 | }
80 |
81 | export default Header;
82 |
--------------------------------------------------------------------------------
/components/Home/index.js:
--------------------------------------------------------------------------------
1 | import { Button } from 'antd';
2 | import Link from 'next/link';
3 |
4 | const Home = () => (
5 |
6 |
26 |
Next-Markdown-Editor
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | );
46 | export default Home;
47 |
--------------------------------------------------------------------------------
/components/Layout.js:
--------------------------------------------------------------------------------
1 | import { Fragment } from 'react';
2 | import PropTypes from 'prop-types';
3 | import IfComp from 'if-comp';
4 | import _ from 'lodash';
5 | import Header from './Header';
6 |
7 | const Layout = ({ pathname, children }) => (
8 |
9 |
22 |
26 |
27 |
28 | {children}
29 |
30 |
31 | }
32 | falseComp={
33 |
40 | {children}
41 |
42 | }
43 | />
44 | }
45 | />
46 |
47 | );
48 |
49 | export default Layout;
50 |
51 | Layout.propTypes = {
52 | pathname: PropTypes.string.isRequired,
53 | children: PropTypes.object.isRequired
54 | };
55 |
56 |
57 |
--------------------------------------------------------------------------------
/components/Normal/SimpleMde.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import SimpleMDE from 'simplemde';
3 | import marked from 'marked';
4 | import hljs from 'highlight.js';
5 | import 'simplemde/dist/simplemde.min.css';
6 | import 'highlight.js/styles/github.css';
7 |
8 | class SimpleMDEditor extends Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = { };
12 | this.smde = null;
13 | }
14 |
15 | componentDidMount() {
16 | // 编辑器内容点击不弹文字
17 | document.getElementById('normalMarkdownEditor')
18 | .parentNode // 获取编辑器container
19 | .addEventListener('click', e => e.stopPropagation());
20 | this.smde = new SimpleMDE({
21 | element: document.getElementById('normalMarkdownEditor').childElementCount,
22 | autofocus: true,
23 | autosave: true,
24 | initialValue: '',
25 | indentWithTabs: false,
26 | placeholder: '## 输入试题内容...',
27 | renderingConfig: {
28 | singleLineBreaks: false,
29 | codeSyntaxHighlighting: true,
30 | },
31 | insertTexts: {
32 | horizontalRule: ["", "\n\n-----\n\n"],
33 | image: [""],
34 | link: ["[", "](http://)"],
35 | table: ["", "\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n"],
36 | },
37 | previewRender: function(plainText) {
38 | return marked(plainText, {
39 | renderer: new marked.Renderer(),
40 | gfm: true,
41 | pedantic: false,
42 | sanitize: false,
43 | tables: true,
44 | breaks: true,
45 | smartLists: true,
46 | smartypants: true,
47 | highlight: function (code) {
48 | return hljs.highlightAuto(code).value;
49 | }
50 | });
51 | },
52 | spellChecker: false
53 | });
54 | }
55 |
56 | render() {
57 | return (
58 |
59 |
60 |
61 | );
62 | }
63 | }
64 |
65 | export default SimpleMDEditor;
--------------------------------------------------------------------------------
/components/Normal/index.js:
--------------------------------------------------------------------------------
1 | import { Fragment } from 'react';
2 | import dynamic from 'next/dynamic';
3 |
4 | const SimpleMDEditor = dynamic(import('./SimpleMde'), {
5 | ssr: false
6 | });
7 |
8 | const NormalEditor = () => (
9 |
10 |
26 | 普通Markdown编辑器
27 |
28 |
29 |
30 |
31 | );
32 |
33 | export default NormalEditor;
--------------------------------------------------------------------------------
/components/Preview/index.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import MarkDown from 'react-markdown';
4 | import marked from 'marked';
5 | import hljs from 'highlight.js';
6 | import 'highlight.js/styles/github.css';
7 |
8 | const initialValue = `
9 | ## Next-Markdown-Editor
10 | \`\`\`
11 | let a;
12 | a = 1;
13 | \`\`\`
14 | 这是一个预览页的Demo
15 | > var a = 1;
16 | `;
17 | class Markdown extends Component {
18 | static propTypes = {
19 | markdownValue: PropTypes.string
20 | }
21 | static defaultProps = {
22 | markdownValue: initialValue
23 | }
24 | constructor(props) {
25 | super(props);
26 | const { markdownValue } = props;
27 | this.state = { markdownValue };
28 | }
29 |
30 | render() {
31 | return (
32 |
33 |
45 |
63 |
64 | );
65 | }
66 | }
67 |
68 | export default Markdown;
--------------------------------------------------------------------------------
/constants/ActionTypes.js:
--------------------------------------------------------------------------------
1 | // ================= 首页部分 ==================== //
2 | export const INCREMENT = 'INCREMENT';
3 | export const DECREMENT = 'DECREMENT';
4 | export const RESET = 'RESET';
5 |
6 | // ================= 用户部分 ==================== //
7 |
8 | export const FETCH_USER_LIST = 'FETCH_USER_LIST';
9 | export const FETCH_USER_LIST_FAIL = 'FETCH_USER_LIST_FAIL';
10 | export const FETCH_USER_LIST_SUCCESS = 'FETCH_USER_LIST_SUCCESS';
--------------------------------------------------------------------------------
/constants/ApiUrlForBE.js:
--------------------------------------------------------------------------------
1 | // const API url
2 |
3 | export default {
4 | /**
5 | * 获取用户列表数据
6 | * @method GET
7 | */
8 | getUserList: '../static/users.json'
9 | };
--------------------------------------------------------------------------------
/constants/ConstTypes.js:
--------------------------------------------------------------------------------
1 | // 用户级别
2 | export const RoleType = {
3 | 1: '管理员',
4 | 10: '普通用户'
5 | };
6 |
7 | // 路由对应页面标题
8 | export const RouterTitle = {
9 | '/': '首页',
10 | '/user/userList': '用户列表',
11 | '/user/userDetail': '用户详情'
12 | };
13 |
14 | export const TagsArray = [
15 | {
16 | name: 'HTML',
17 | url: '/static/tags/HTML.png'
18 | }, {
19 | name: 'JavaScript',
20 | url: '/static/tags/JavaScript.png'
21 | }, {
22 | name: 'CSS',
23 | url: '/static/tags/CSS.png'
24 | }, {
25 | name: '前端',
26 | url: '/static/tags/WEB.png'
27 | }, {
28 | name: 'React',
29 | url: '/static/tags/React.png'
30 | }, {
31 | name: 'Vue',
32 | url: '/static/tags/Vue.png'
33 | }, {
34 | name: 'Angular',
35 | url: '/static/tags/Angular.png'
36 | }, {
37 | name: 'Webpack',
38 | url: '/static/tags/Webpack.png'
39 | }, {
40 | name: 'Nodejs',
41 | url: '/static/tags/Nodejs.png'
42 | }, {
43 | name: '后端',
44 | url: '/static/tags/Back.png'
45 | }, {
46 | name: 'Java',
47 | url: '/static/tags/Java.png'
48 | }, {
49 | name: '产品',
50 | url: '/static/tags/Product.png'
51 | }, {
52 | name: '数据库',
53 | url: '/static/tags/Database.png'
54 | }, {
55 | name: '算法',
56 | url: '/static/tags/Algorithm.png'
57 | }, {
58 | name: 'Python',
59 | url: '/static/tags/Python.png'
60 | }, {
61 | name: 'Http',
62 | url: '/static/tags/Http.png'
63 | },
64 | ];
--------------------------------------------------------------------------------
/constants/CustomTheme.js:
--------------------------------------------------------------------------------
1 | /* 各种颜色常量 */
2 | export const color_youdao = '#E93D34';
3 | export const color_youdao_border = '#c20c0c';
4 | export const color_primary = '#53f';
5 |
6 |
--------------------------------------------------------------------------------
/containers/home/counter.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import { increment, decrement, reset } from '../../redux/actions/home';
3 | import Counter from '../../components/Home/Counter';
4 |
5 | const mapStateToProps = state => ({
6 | count: state.home.counter.count,
7 | });
8 |
9 | const mapDispatchToProps = dispatch => ({
10 | increment() {
11 | dispatch(increment());
12 | },
13 | decrement() {
14 | dispatch(decrement());
15 | },
16 | reset() {
17 | dispatch(reset());
18 | }
19 | });
20 |
21 | export default connect(mapStateToProps, mapDispatchToProps)(Counter);
22 |
--------------------------------------------------------------------------------
/containers/user/UserList.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import { fetchUserListData } from '../../redux/actions/user';
3 | import UserList from '../../components/User/UserList';
4 |
5 | const mapStateToProps = state => ({
6 | list: state.user.list.list,
7 | });
8 |
9 | const mapDispatchToProps = dispatch => ({
10 | fetchUserListData() {
11 | dispatch(fetchUserListData());
12 | }
13 | });
14 |
15 | export default connect(mapStateToProps, mapDispatchToProps)(UserList);
16 |
--------------------------------------------------------------------------------
/core/nextFetch.js:
--------------------------------------------------------------------------------
1 | import fetch from 'isomorphic-unfetch';
2 | import qs from 'query-string';
3 | import { filterObject } from './util';
4 |
5 | // initial fetch
6 | const nextFetch = Object.create(null);
7 | // browser support methods
8 | // ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PATCH', 'PUT']
9 | const HTTP_METHOD = ['get', 'post', 'put', 'patch', 'delete'];
10 | // can send data method
11 | const CAN_SEND_METHOD = ['post', 'put', 'delete', 'patch'];
12 |
13 | HTTP_METHOD.forEach(method => {
14 | // is can send data in opt.body
15 | const canSend = CAN_SEND_METHOD.includes(method);
16 | nextFetch[method] = (path, { data, query, timeout = 10000 } = {}) => {
17 | let url = path;
18 | const opts = {
19 | method,
20 | headers: {
21 | 'Content-Type': 'application/x-www-form-urlencoded',
22 | Accept: 'application/json'
23 | },
24 | credentials: 'include',
25 | timeout,
26 | mode: 'same-origin',
27 | cache: 'no-cache'
28 | };
29 |
30 | if (query) {
31 | url += `${url.includes('?') ? '&' : '?'}${qs.stringify(
32 | filterObject(query, Boolean),
33 | )}`;
34 | }
35 |
36 | if (canSend && data) {
37 | opts.body = qs.stringify(filterObject(data, Boolean));
38 | }
39 |
40 | console.info('Request Url:', url);
41 |
42 | return fetch(url, opts)
43 | .then(res => res.json())
44 | .then(({ errcode = 0, errmsg, data }) => {
45 | if (errcode !== 0) {
46 | const err = new Error(errmsg);
47 | err.message = errmsg;
48 | err.code = errcode;
49 | err.data = data;
50 | throw err;
51 | }
52 | return data;
53 | });
54 | };
55 | });
56 |
57 | export default nextFetch;
--------------------------------------------------------------------------------
/core/util.js:
--------------------------------------------------------------------------------
1 | // transform the http query & params
2 | export const filterObject = (o, filter) => {
3 | const r = {};
4 | Object.keys(o).forEach(k => {
5 | if (filter(o[k], k)) {
6 | r[k] = o[k];
7 | }
8 | });
9 | return r;
10 | };
--------------------------------------------------------------------------------
/middlewares/client/user.js:
--------------------------------------------------------------------------------
1 | import { message } from 'antd';
2 | import {
3 | FETCH_USER_LIST_FAIL
4 | } from '../../constants/ActionTypes';
5 |
6 | export default ({ getState }) => next => action => {
7 | console.log(getState());
8 | const ret = next(action);
9 | switch (action.type) {
10 | case FETCH_USER_LIST_FAIL: {
11 | message.error('获取用户列表失败, 请稍后重试');
12 | break;
13 | }
14 | default:
15 | }
16 | return ret;
17 | };
18 |
--------------------------------------------------------------------------------
/middlewares/server/README.md:
--------------------------------------------------------------------------------
1 | ### deal request in node, like download file stream etc...
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | const withLess = require('@zeit/next-less');
3 | const withCss = require('@zeit/next-css');
4 | const lessToJS = require('less-vars-to-js');
5 | const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
6 | const TerserPlugin = require('terser-webpack-plugin');
7 | const fs = require('fs');
8 | const path = require('path');
9 |
10 | // Where your antd-custom.less file lives
11 | const themeVariables = lessToJS(
12 | fs.readFileSync(
13 | path.resolve(__dirname, './asserts/antd-custom.less'),
14 | 'utf8',
15 | ),
16 | );
17 |
18 | // fix: prevents error when .css files are required by node
19 | if (typeof require !== 'undefined') {
20 | require.extensions['.less'] = (file) => {}
21 | }
22 |
23 | module.exports = withCss(withLess({
24 | exportPathMap: async function (defaultPathMap) {
25 | return {
26 | '/': { page: '/' },
27 | '/normal': { page: '/normal' },
28 | '/edit': { page: '/edit' },
29 | '/preview': { page: '/preview' }
30 | }
31 | },
32 | lessLoaderOptions: {
33 | javascriptEnabled: true,
34 | modifyVars: themeVariables,
35 | localIdentName: '[local]___[hash:base64:5]',
36 | },
37 | webpack: (config, { buildId, dev, isServer, defaultLoaders }) => {
38 | if (!dev) {
39 | config.plugins.push(
40 | ...[
41 | new BundleAnalyzerPlugin({
42 | analyzerMode: 'disabled',
43 | // For all options see https://github.com/th0r/webpack-bundle-analyzer#as-plugin
44 | generateStatsFile: true,
45 | // Will be available at `.next/stats.json`
46 | statsFilename: 'stats.json'
47 | }),
48 | // 代替uglyJsPlugin
49 | new TerserPlugin({
50 | terserOptions: {
51 | ecma: 6,
52 | warnings: false,
53 | extractComments: false, // remove comment
54 | compress: {
55 | drop_console: true // remove console
56 | },
57 | ie8: false
58 | }
59 | }),
60 | ]);
61 | config.devtool = 'source-map';
62 | } else {
63 | config.module.rules.push({
64 | test: /\.js$/,
65 | enforce: 'pre',
66 | include: [
67 | path.resolve('components'),
68 | path.resolve('pages'),
69 | path.resolve('utils'),
70 | path.resolve('constants'),
71 | path.resolve('redux'),
72 | path.resolve('containers')
73 | ],
74 | options: {
75 | configFile: path.resolve('.eslintrc'),
76 | eslint: {
77 | configFile: path.resolve(__dirname, '.eslintrc')
78 | }
79 | },
80 | loader: 'eslint-loader'
81 | });
82 | config.devtool = 'cheap-module-inline-source-map';
83 | }
84 | return config;
85 | },
86 | webpackDevMiddleware: config => {
87 | // Perform customizations to webpack dev middleware config
88 | // console.log(config, '@@')
89 | // Important: return the modified config
90 | return config;
91 | }
92 | }));
--------------------------------------------------------------------------------
/out/_next/static/NSy5qE4UvMw4dCrM10co1/pages/_error.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[5],{123:function(e,t,n){e.exports=n(46)},339:function(e,t,n){__NEXT_REGISTER_PAGE("/_error",function(){return e.exports=n(632),{page:e.exports.default}})},632:function(e,t,n){"use strict";n.r(t);var r=n(0),o=n.n(r),i=(n(1),n(110),n(34)),c=n.n(i),a=n(3),u=n.n(a),s=n(123),l=n.n(s);function f(e){return(f="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function p(e,t){for(var n=0;n1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,l=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;i||(i=document.createElement("textarea"),document.body.appendChild(i)),e.getAttribute("wrap")?i.setAttribute("wrap",e.getAttribute("wrap")):i.removeAttribute("wrap");var u=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=e.getAttribute("id")||e.getAttribute("data-reactid")||e.getAttribute("name");if(t&&o[n])return o[n];var r=window.getComputedStyle(e),i=r.getPropertyValue("box-sizing")||r.getPropertyValue("-moz-box-sizing")||r.getPropertyValue("-webkit-box-sizing"),l=parseFloat(r.getPropertyValue("padding-bottom"))+parseFloat(r.getPropertyValue("padding-top")),u=parseFloat(r.getPropertyValue("border-bottom-width"))+parseFloat(r.getPropertyValue("border-top-width")),s={sizingStyle:a.map(function(e){return e+":"+r.getPropertyValue(e)}).join(";"),paddingSize:l,borderSize:u,boxSizing:i};return t&&n&&(o[n]=s),s}(e,t),s=u.paddingSize,f=u.borderSize,d=u.boxSizing,p=u.sizingStyle;i.setAttribute("style",p+";"+r),i.value=e.value||e.placeholder||"";var c=Number.MIN_SAFE_INTEGER,m=Number.MAX_SAFE_INTEGER,y=i.scrollHeight,h=void 0;if("border-box"===d?y+=f:"content-box"===d&&(y-=s),null!==n||null!==l){i.value=" ";var b=i.scrollHeight-s;null!==n&&(c=b*n,"border-box"===d&&(c=c+s+f),y=Math.max(c,y)),null!==l&&(m=b*l,"border-box"===d&&(m=m+s+f),h=y>m?"":"hidden",y=Math.min(m,y))}return l||(h="hidden"),{height:y,minHeight:c,maxHeight:m,overflowY:h}};var r="\n min-height:0 !important;\n max-height:none !important;\n height:0 !important;\n visibility:hidden !important;\n overflow:hidden !important;\n position:absolute !important;\n z-index:-1000 !important;\n top:0 !important;\n right:0 !important\n",a=["letter-spacing","line-height","padding-top","padding-bottom","font-family","font-weight","font-size","text-rendering","text-transform","width","text-indent","padding-left","padding-right","border-width","box-sizing"],o={},i=void 0;e.exports=t.default},60:function(e,t,n){e.exports=n(111)},631:function(e,t,n){"use strict";n.r(t),n(347);var r=n(185),a=n.n(r),o=n(3),i=n.n(o),l=n(0),u=n.n(l),s=n(60);function f(e){return(f="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function d(e,t){for(var n=0;n0&&void 0!==n[0]?n[0]:{}).webpackHMR,e.next=4,N.loadPage("/_error");case 4:return t.ErrorComponent=L=e.sent,e.next=7,N.loadPage("/_app");case 7:return H=e.sent,r=C,e.prev=9,e.next=12,N.loadPage(P);case 12:if("function"==typeof(G=e.sent)){e.next=15;break}throw new Error('The default export is not a React Component in page: "'.concat(P,'"'));case 15:e.next=20;break;case 17:e.prev=17,e.t0=e.catch(9),r=e.t0;case 20:return e.next=22,_.default.preloadReady(T||[]);case 22:return t.router=j=(0,f.createRouter)(P,b,M,{initialProps:x,pageLoader:N,App:H,Component:G,ErrorComponent:L,err:r}),j.subscribe(function(e){z({App:e.App,Component:e.Component,props:e.props,err:e.err,emitter:D})}),z({App:H,Component:G,props:x,err:r,emitter:D}),e.abrupt("return",D);case 26:case"end":return e.stop()}},e,this,[[9,17]])}));function z(e){return function(){return(0,i.default)(u.default.mark(function e(t){return u.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(!t.err){e.next=4;break}return e.next=3,B(t);case 3:return e.abrupt("return");case 4:return e.prev=4,e.next=7,J(t);case 7:e.next=13;break;case 9:return e.prev=9,e.t0=e.catch(4),e.next=13,B((0,o.default)({},t,{err:e.t0}));case 13:case"end":return e.stop()}},e,this,[[4,9]])})).apply(this,arguments)}.apply(this,arguments)}function B(e){return function(){return(0,i.default)(u.default.mark(function e(t){var r,n,a;return u.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:r=t.App,n=t.err,e.next=3;break;case 3:if(!t.props){e.next=8;break}e.t0=t.props,e.next=11;break;case 8:return e.next=10,(0,v.loadGetInitialProps)(r,{Component:L,router:j,ctx:{err:n,pathname:P,query:b,asPath:M}});case 10:e.t0=e.sent;case 11:return a=e.t0,e.next=14,J((0,o.default)({},t,{err:n,Component:L,props:a}));case 14:case"end":return e.stop()}},e,this)})).apply(this,arguments)}.apply(this,arguments)}t.default=X;var U=!0;function J(e){return function(){return(0,i.default)(u.default.mark(function e(t){var r,n,a,s,c,l,f,h,m,g,y,_;return u.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(r=t.App,n=t.Component,a=t.props,s=t.err,c=t.emitter,l=void 0===c?D:c,a||!n||n===L||O.Component!==L){e.next=6;break}return h=(f=j).pathname,m=f.query,g=f.asPath,e.next=5,(0,v.loadGetInitialProps)(r,{Component:n,router:j,ctx:{err:s,pathname:h,query:m,asPath:g}});case 5:a=e.sent;case 6:n=n||O.Component,a=a||O.props,y=(0,o.default)({Component:n,err:s,router:j,headManager:S},a),O=y,l.emit("before-reactdom-render",{Component:n,ErrorComponent:L,appProps:y}),_=function(){var e=(0,i.default)(u.default.mark(function e(t){return u.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.prev=0,e.next=3,B({App:r,err:t});case 3:e.next=8;break;case 5:e.prev=5,e.t0=e.catch(0);case 8:case"end":return e.stop()}},e,this,[[0,5]])}));return function(t){return e.apply(this,arguments)}}(),w=p.default.createElement(E.default,{onError:_},p.default.createElement(r,y)),x=q,U&&"function"==typeof d.default.hydrate?(d.default.hydrate(w,x),U=!1):d.default.render(w,x),l.emit("after-reactdom-render",{Component:n,ErrorComponent:L,appProps:y});case 13:case"end":return e.stop()}var w,x},e,this)})).apply(this,arguments)}.apply(this,arguments)}},225:function(e,t,r){"use strict";var n=r(5);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=n(r(43)),o=n(r(11)),u=n(r(12)),i={acceptCharset:"accept-charset",className:"class",htmlFor:"for",httpEquiv:"http-equiv"},s=function(){function e(){(0,o.default)(this,e),this.updatePromise=null}return(0,u.default)(e,[{key:"updateHead",value:function(e){var t=this,r=this.updatePromise=a.default.resolve().then(function(){r===t.updatePromise&&(t.updatePromise=null,t.doUpdateHead(e))})}},{key:"doUpdateHead",value:function(e){var t=this,r={};e.forEach(function(e){var t=r[e.type]||[];t.push(e),r[e.type]=t}),this.updateTitle(r.title?r.title[0]:null),["meta","base","link","style","script"].forEach(function(e){t.updateElements(e,r[e]||[])})}},{key:"updateTitle",value:function(e){var t;if(e){var r=e.props.children;t="string"==typeof r?r:r.join("")}else t="";t!==document.title&&(document.title=t)}},{key:"updateElements",value:function(e,t){var r=document.getElementsByTagName("head")[0],n=Array.prototype.slice.call(r.querySelectorAll(e+".next-head")),a=t.map(c).filter(function(e){for(var t=0,r=n.length;tNext-Markdown-Editor
--------------------------------------------------------------------------------
/out/index.html:
--------------------------------------------------------------------------------
1 | Next-Markdown-Editor
--------------------------------------------------------------------------------
/out/normal/index.html:
--------------------------------------------------------------------------------
1 | Next-Markdown-Editor
--------------------------------------------------------------------------------
/out/preview/index.html:
--------------------------------------------------------------------------------
1 | Next-Markdown-EditorNext-Markdown-Editor
16 |
let a
17 | a = 1
这是一个预览页的Demo
18 |
19 | var a = 1;
20 |
--------------------------------------------------------------------------------
/out/static/empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/empty.png
--------------------------------------------------------------------------------
/out/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/favicon.ico
--------------------------------------------------------------------------------
/out/static/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/logo.png
--------------------------------------------------------------------------------
/out/static/tags/Algorithm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/Algorithm.png
--------------------------------------------------------------------------------
/out/static/tags/Angular.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/Angular.png
--------------------------------------------------------------------------------
/out/static/tags/Back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/Back.png
--------------------------------------------------------------------------------
/out/static/tags/CSS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/CSS.png
--------------------------------------------------------------------------------
/out/static/tags/Database.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/Database.png
--------------------------------------------------------------------------------
/out/static/tags/HTML.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/HTML.png
--------------------------------------------------------------------------------
/out/static/tags/Http.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/Http.png
--------------------------------------------------------------------------------
/out/static/tags/Java.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/Java.png
--------------------------------------------------------------------------------
/out/static/tags/JavaScript.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/JavaScript.png
--------------------------------------------------------------------------------
/out/static/tags/Nodejs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/Nodejs.png
--------------------------------------------------------------------------------
/out/static/tags/Product.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/Product.png
--------------------------------------------------------------------------------
/out/static/tags/Python.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/Python.png
--------------------------------------------------------------------------------
/out/static/tags/React.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/React.png
--------------------------------------------------------------------------------
/out/static/tags/Vue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/Vue.png
--------------------------------------------------------------------------------
/out/static/tags/WEB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/WEB.png
--------------------------------------------------------------------------------
/out/static/tags/Webpack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/tags/Webpack.png
--------------------------------------------------------------------------------
/out/static/unknown_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/out/static/unknown_error.png
--------------------------------------------------------------------------------
/out/static/users.json:
--------------------------------------------------------------------------------
1 | {
2 | "errcode": 500,
3 | "errmsg": "服务器内部错误",
4 | "data": [
5 | {
6 | "id": 1,
7 | "name": "Leanne Graham",
8 | "username": "Bret",
9 | "email": "Sincere@april.biz",
10 | "address": {
11 | "street": "Kulas Light",
12 | "suite": "Apt. 556",
13 | "city": "Gwenborough",
14 | "zipcode": "92998-3874",
15 | "geo": {
16 | "lat": "-37.3159",
17 | "lng": "81.1496"
18 | }
19 | },
20 | "phone": "1-770-736-8031 x56442",
21 | "website": "hildegard.org",
22 | "company": {
23 | "name": "Romaguera-Crona",
24 | "catchPhrase": "Multi-layered client-server neural-net",
25 | "bs": "harness real-time e-markets"
26 | }
27 | },
28 | {
29 | "id": 2,
30 | "name": "Ervin Howell",
31 | "username": "Antonette",
32 | "email": "Shanna@melissa.tv",
33 | "address": {
34 | "street": "Victor Plains",
35 | "suite": "Suite 879",
36 | "city": "Wisokyburgh",
37 | "zipcode": "90566-7771",
38 | "geo": {
39 | "lat": "-43.9509",
40 | "lng": "-34.4618"
41 | }
42 | },
43 | "phone": "010-692-6593 x09125",
44 | "website": "anastasia.net",
45 | "company": {
46 | "name": "Deckow-Crist",
47 | "catchPhrase": "Proactive didactic contingency",
48 | "bs": "synergize scalable supply-chains"
49 | }
50 | },
51 | {
52 | "id": 3,
53 | "name": "Clementine Bauch",
54 | "username": "Samantha",
55 | "email": "Nathan@yesenia.net",
56 | "address": {
57 | "street": "Douglas Extension",
58 | "suite": "Suite 847",
59 | "city": "McKenziehaven",
60 | "zipcode": "59590-4157",
61 | "geo": {
62 | "lat": "-68.6102",
63 | "lng": "-47.0653"
64 | }
65 | },
66 | "phone": "1-463-123-4447",
67 | "website": "ramiro.info",
68 | "company": {
69 | "name": "Romaguera-Jacobson",
70 | "catchPhrase": "Face to face bifurcated interface",
71 | "bs": "e-enable strategic applications"
72 | }
73 | },
74 | {
75 | "id": 4,
76 | "name": "Patricia Lebsack",
77 | "username": "Karianne",
78 | "email": "Julianne.OConner@kory.org",
79 | "address": {
80 | "street": "Hoeger Mall",
81 | "suite": "Apt. 692",
82 | "city": "South Elvis",
83 | "zipcode": "53919-4257",
84 | "geo": {
85 | "lat": "29.4572",
86 | "lng": "-164.2990"
87 | }
88 | },
89 | "phone": "493-170-9623 x156",
90 | "website": "kale.biz",
91 | "company": {
92 | "name": "Robel-Corkery",
93 | "catchPhrase": "Multi-tiered zero tolerance productivity",
94 | "bs": "transition cutting-edge web services"
95 | }
96 | },
97 | {
98 | "id": 5,
99 | "name": "Chelsey Dietrich",
100 | "username": "Kamren",
101 | "email": "Lucio_Hettinger@annie.ca",
102 | "address": {
103 | "street": "Skiles Walks",
104 | "suite": "Suite 351",
105 | "city": "Roscoeview",
106 | "zipcode": "33263",
107 | "geo": {
108 | "lat": "-31.8129",
109 | "lng": "62.5342"
110 | }
111 | },
112 | "phone": "(254)954-1289",
113 | "website": "demarco.info",
114 | "company": {
115 | "name": "Keebler LLC",
116 | "catchPhrase": "User-centric fault-tolerant solution",
117 | "bs": "revolutionize end-to-end systems"
118 | }
119 | },
120 | {
121 | "id": 6,
122 | "name": "Mrs. Dennis Schulist",
123 | "username": "Leopoldo_Corkery",
124 | "email": "Karley_Dach@jasper.info",
125 | "address": {
126 | "street": "Norberto Crossing",
127 | "suite": "Apt. 950",
128 | "city": "South Christy",
129 | "zipcode": "23505-1337",
130 | "geo": {
131 | "lat": "-71.4197",
132 | "lng": "71.7478"
133 | }
134 | },
135 | "phone": "1-477-935-8478 x6430",
136 | "website": "ola.org",
137 | "company": {
138 | "name": "Considine-Lockman",
139 | "catchPhrase": "Synchronised bottom-line interface",
140 | "bs": "e-enable innovative applications"
141 | }
142 | },
143 | {
144 | "id": 7,
145 | "name": "Kurtis Weissnat",
146 | "username": "Elwyn.Skiles",
147 | "email": "Telly.Hoeger@billy.biz",
148 | "address": {
149 | "street": "Rex Trail",
150 | "suite": "Suite 280",
151 | "city": "Howemouth",
152 | "zipcode": "58804-1099",
153 | "geo": {
154 | "lat": "24.8918",
155 | "lng": "21.8984"
156 | }
157 | },
158 | "phone": "210.067.6132",
159 | "website": "elvis.io",
160 | "company": {
161 | "name": "Johns Group",
162 | "catchPhrase": "Configurable multimedia task-force",
163 | "bs": "generate enterprise e-tailers"
164 | }
165 | },
166 | {
167 | "id": 8,
168 | "name": "Nicholas Runolfsdottir V",
169 | "username": "Maxime_Nienow",
170 | "email": "Sherwood@rosamond.me",
171 | "address": {
172 | "street": "Ellsworth Summit",
173 | "suite": "Suite 729",
174 | "city": "Aliyaview",
175 | "zipcode": "45169",
176 | "geo": {
177 | "lat": "-14.3990",
178 | "lng": "-120.7677"
179 | }
180 | },
181 | "phone": "586.493.6943 x140",
182 | "website": "jacynthe.com",
183 | "company": {
184 | "name": "Abernathy Group",
185 | "catchPhrase": "Implemented secondary concept",
186 | "bs": "e-enable extensible e-tailers"
187 | }
188 | },
189 | {
190 | "id": 9,
191 | "name": "Glenna Reichert",
192 | "username": "Delphine",
193 | "email": "Chaim_McDermott@dana.io",
194 | "address": {
195 | "street": "Dayna Park",
196 | "suite": "Suite 449",
197 | "city": "Bartholomebury",
198 | "zipcode": "76495-3109",
199 | "geo": {
200 | "lat": "24.6463",
201 | "lng": "-168.8889"
202 | }
203 | },
204 | "phone": "(775)976-6794 x41206",
205 | "website": "conrad.com",
206 | "company": {
207 | "name": "Yost and Sons",
208 | "catchPhrase": "Switchable contextually-based project",
209 | "bs": "aggregate real-time technologies"
210 | }
211 | },
212 | {
213 | "id": 10,
214 | "name": "Clementina DuBuque",
215 | "username": "Moriah.Stanton",
216 | "email": "Rey.Padberg@karina.biz",
217 | "address": {
218 | "street": "Kattie Turnpike",
219 | "suite": "Suite 198",
220 | "city": "Lebsackbury",
221 | "zipcode": "31428-2261",
222 | "geo": {
223 | "lat": "-38.2386",
224 | "lng": "57.2232"
225 | }
226 | },
227 | "phone": "024-648-3804",
228 | "website": "ambrose.net",
229 | "company": {
230 | "name": "Hoeger LLC",
231 | "catchPhrase": "Centralized empowering task-force",
232 | "bs": "target end-to-end models"
233 | }
234 | }
235 | ]
236 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "first-next-demo",
3 | "version": "1.0.0",
4 | "description": "first nextjs demo",
5 | "main": "index.js",
6 | "author": "luffyZhou",
7 | "license": "MIT",
8 | "scripts": {
9 | "start": "node server.js",
10 | "build": "next build",
11 | "prod": "NODE_ENV=production node server.js",
12 | "preexport": "next build",
13 | "export": "next export",
14 | "static-run": "next export && serve out",
15 | "deploy": "rm -rf node_modules/.cache && next build && next export && touch out/.nojekyll && git add out/ && git commit -m \"Deploy Next.js to gh-pages\" && git subtree push --prefix out origin gh-pages"
16 | },
17 | "dependencies": {
18 | "@zeit/next-css": "^1.0.1",
19 | "@zeit/next-less": "^1.0.1",
20 | "antd": "^3.8.4",
21 | "babel-plugin-import": "^1.9.0",
22 | "es6-promise": "^4.2.5",
23 | "express": "^4.16.3",
24 | "highlight.js": "^9.13.1",
25 | "if-comp": "^0.0.8",
26 | "isomorphic-unfetch": "^3.0.0",
27 | "less": "^3.8.1",
28 | "less-vars-to-js": "^1.3.0",
29 | "lodash": "^4.17.11",
30 | "marked": "^0.6.2",
31 | "next": "^7.0.2",
32 | "next-redux-saga": "^3.0.0",
33 | "next-redux-wrapper": "^2.0.0",
34 | "prop-types": "^15.6.2",
35 | "query-string": "^6.2.0",
36 | "react": "^16.5.0",
37 | "react-dom": "^16.5.0",
38 | "react-markdown": "^4.0.4",
39 | "react-redux": "^5.0.7",
40 | "redux": "^4.0.0",
41 | "redux-logger": "^3.0.6",
42 | "redux-saga": "^0.16.0",
43 | "serve": "^10.1.1",
44 | "simplemde": "^1.11.2"
45 | },
46 | "devDependencies": {
47 | "@babel/plugin-proposal-decorators": "^7.1.0",
48 | "babel-eslint": "^9.0.0",
49 | "babel-plugin-lodash": "^3.3.4",
50 | "eslint": "^5.4.0",
51 | "eslint-config-react-app": "^2.1.0",
52 | "eslint-loader": "^2.1.0",
53 | "eslint-plugin-flowtype": "^2.50.0",
54 | "eslint-plugin-import": "^2.14.0",
55 | "eslint-plugin-jsx-a11y": "^6.1.1",
56 | "eslint-plugin-react": "^7.11.1",
57 | "redux-devtools-extension": "^2.13.5",
58 | "terser-webpack-plugin": "^1.1.0",
59 | "webpack-bundle-analyzer": "^3.3.2"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | import { Fragment } from 'react';
2 | import App, { Container } from 'next/app';
3 | import Head from 'next/head';
4 | import { Provider } from 'react-redux';
5 | import withRedux from 'next-redux-wrapper';
6 | import withReduxSaga from 'next-redux-saga';
7 | import createStore from '../redux/store';
8 | import Layout from '../components/Layout';
9 | import '../asserts/styles.less';
10 | class InTerViewSystem extends App {
11 |
12 | static async getInitialProps ({ Component, ctx }) {
13 | let pageProps = {};
14 |
15 | if (Component.getInitialProps) {
16 | pageProps = await Component.getInitialProps({ ctx });
17 | }
18 |
19 | return { pageProps };
20 | }
21 |
22 | render () {
23 | const { Component, pageProps, store, router } = this.props;
24 | return (
25 |
26 |
27 |
28 |
29 | Next-Markdown-Editor
30 |
31 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | );
51 | }
52 | }
53 |
54 | export default withRedux(createStore)(withReduxSaga({ async: true })(InTerViewSystem));
--------------------------------------------------------------------------------
/pages/_document.js:
--------------------------------------------------------------------------------
1 | // _document is only rendered on the server side and not on the client side
2 | // Event handlers like onClick can't be added to this file
3 |
4 | // ./pages/_document.js
5 | import Document, { Head, Main, NextScript } from 'next/document';
6 |
7 | export default class MyDocument extends Document {
8 | static async getInitialProps(ctx) {
9 | const initialProps = await Document.getInitialProps(ctx);
10 | return { ...initialProps };
11 | }
12 |
13 | render() {
14 | return (
15 |
16 |
17 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 | }
--------------------------------------------------------------------------------
/pages/_error.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import ErrorPage from '../components/ErrorPage';
4 | export default class Error extends React.Component {
5 | static propTypes = {
6 | statusCode: PropTypes.number
7 | }
8 | static defaultProps = {
9 | statusCode: 200
10 | }
11 | static getInitialProps({ res, err }) {
12 | const statusCode = res ? res.statusCode : err ? err.statusCode : null;
13 | return { statusCode };
14 | }
15 |
16 | render() {
17 | return (
18 |
19 | );
20 | }
21 | }
--------------------------------------------------------------------------------
/pages/edit/index.js:
--------------------------------------------------------------------------------
1 | import Edit from '../../components/Edit';
2 |
3 | export default Edit;
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import Home from '../components/Home';
2 |
3 | export default Home;
--------------------------------------------------------------------------------
/pages/normal/index.js:
--------------------------------------------------------------------------------
1 | import Normal from '../../components/Normal';
2 |
3 | export default Normal;
--------------------------------------------------------------------------------
/pages/preview/index.js:
--------------------------------------------------------------------------------
1 | import Preview from '../../components/Preview';
2 |
3 | export default Preview;
--------------------------------------------------------------------------------
/redux/actions/home.js:
--------------------------------------------------------------------------------
1 | import {
2 | INCREMENT,
3 | DECREMENT,
4 | RESET
5 | } from '../../constants/ActionTypes';
6 |
7 | export function increment () {
8 | return {
9 | type: INCREMENT
10 | };
11 | }
12 |
13 | export function decrement () {
14 | return {
15 | type: DECREMENT
16 | };
17 | }
18 |
19 | export function reset () {
20 | return {
21 | type: RESET
22 | };
23 | }
--------------------------------------------------------------------------------
/redux/actions/user.js:
--------------------------------------------------------------------------------
1 | import {
2 | FETCH_USER_LIST,
3 | FETCH_USER_LIST_FAIL,
4 | FETCH_USER_LIST_SUCCESS
5 | } from '../../constants/ActionTypes';
6 |
7 | export function fetchUserListData () {
8 | return {
9 | type: FETCH_USER_LIST
10 | };
11 | }
12 |
13 | export function fetchUserListDataSuccess (payload) {
14 | return {
15 | type: FETCH_USER_LIST_SUCCESS,
16 | payload
17 | };
18 | }
19 |
20 | export function fetchUserListDataFali () {
21 | return {
22 | type: FETCH_USER_LIST_FAIL,
23 | };
24 | }
--------------------------------------------------------------------------------
/redux/reducers/home/counter.js:
--------------------------------------------------------------------------------
1 | import {
2 | INCREMENT,
3 | DECREMENT,
4 | RESET
5 | } from '../../../constants/ActionTypes';
6 |
7 | const initialState = {
8 | count: 0
9 | };
10 |
11 | const counter = (state = initialState, { type }) => {
12 | switch (type) {
13 | case INCREMENT:
14 | return {
15 | ...state,
16 | count: state.count + 1
17 | };
18 | case DECREMENT:
19 | return {
20 | ...state,
21 | count: state.count - 1
22 | };
23 | case RESET:
24 | return {
25 | ...state,
26 | count: 0
27 | };
28 | default:
29 | return state;
30 | }
31 | };
32 |
33 | export default counter;
34 |
--------------------------------------------------------------------------------
/redux/reducers/home/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import counter from './counter';
3 |
4 | export default combineReducers({
5 | counter
6 | });
--------------------------------------------------------------------------------
/redux/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import home from './home';
3 | import user from './user';
4 |
5 | export default combineReducers({
6 | home,
7 | user
8 | });
--------------------------------------------------------------------------------
/redux/reducers/user/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import list from './list';
3 |
4 | export default combineReducers({
5 | list
6 | });
--------------------------------------------------------------------------------
/redux/reducers/user/list.js:
--------------------------------------------------------------------------------
1 | import {
2 | FETCH_USER_LIST,
3 | FETCH_USER_LIST_FAIL,
4 | FETCH_USER_LIST_SUCCESS
5 | } from '../../../constants/ActionTypes';
6 |
7 | const initialState = {
8 | list: []
9 | };
10 |
11 | const list = (state = initialState, { type, payload }) => {
12 | switch (type) {
13 | case FETCH_USER_LIST:
14 | case FETCH_USER_LIST_FAIL:
15 | return initialState;
16 | case FETCH_USER_LIST_SUCCESS:
17 | return {
18 | ...state,
19 | list: payload
20 | };
21 | default:
22 | return state;
23 | }
24 | };
25 |
26 | export default list;
27 |
--------------------------------------------------------------------------------
/redux/sagas/index.js:
--------------------------------------------------------------------------------
1 | import { all } from 'redux-saga/effects';
2 | import userSagas from './user/index';
3 |
4 |
5 | export default function* rootSagas() {
6 | yield all([
7 | ...userSagas
8 | ]);
9 | }
10 |
--------------------------------------------------------------------------------
/redux/sagas/user/index.js:
--------------------------------------------------------------------------------
1 |
2 | import userList from './userList';
3 |
4 | const userSagas = [
5 | ...userList,
6 | ];
7 |
8 | export default userSagas;
--------------------------------------------------------------------------------
/redux/sagas/user/userList.js:
--------------------------------------------------------------------------------
1 | import { take, put, fork } from 'redux-saga/effects';
2 | import {
3 | FETCH_USER_LIST,
4 | } from '../../../constants/ActionTypes';
5 | import { fetchUserListDataFali, fetchUserListDataSuccess } from '../../actions/user';
6 | import api from '../../../constants/ApiUrlForBE';
7 | import nextFetch from '../../../core/nextFetch';
8 | /**
9 | * 简洁的实际写法, 把worker saga和watcher saga结合在一起。写起来方便
10 | */
11 | export function* userList() {
12 | while (true) {
13 | yield take(FETCH_USER_LIST);
14 | try {
15 | const data = yield nextFetch.get(api.getUserList);
16 | // const res = yield fetch(api.getUserList);
17 | // const { data } = yield res.json();
18 | yield put(fetchUserListDataSuccess(data));
19 | } catch (error) {
20 | console.log(error.code, error.message, error.data);
21 | yield put(fetchUserListDataFali(error));
22 | }
23 | }
24 | }
25 |
26 | /**
27 | * 合理的官方写法,分离了watcher saga和worker saga
28 | */
29 | // // worker saga
30 | // export function* getUserList() {
31 | // try {
32 | // const { data } = yield call(http.get, apiUrl.USER_LIST);
33 | // yield put({ type: FETCH_ALL_USER_LIST_SUCCESS, payload: data });
34 | // } catch(error) {
35 | // yield put({ type: FETCH_ALL_USER_LIST_FAIL, payload: error });
36 | // }
37 | // }
38 | // // watcher saga
39 | // export function* watchGetUserList() {
40 | // yield takeEvery(FETCH_ALL_USER_LIST, getUserList);
41 | // }
42 |
43 | export default [
44 | fork(userList)
45 | ];
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/redux/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware } from 'redux';
2 | import createSagaMiddleware from 'redux-saga';
3 | import rootReducer from './reducers/index';
4 | import rootSaga from './sagas/index';
5 | import userMiddleware from '../middlewares/client/user';
6 |
7 | const sagaMiddleware = createSagaMiddleware();
8 |
9 | const bindMiddleware = (middleware) => {
10 | // add route middleware
11 | middleware.push(userMiddleware);
12 | if (process.env.NODE_ENV !== 'production') {
13 | const { composeWithDevTools } = require('redux-devtools-extension');
14 | // 开发模式打印redux信息
15 | const { logger } = require('redux-logger');
16 | middleware.push(logger);
17 | return composeWithDevTools(applyMiddleware(...middleware));
18 | }
19 | return applyMiddleware(...middleware);
20 | };
21 |
22 | function configureStore (initialState) {
23 | const store = createStore(
24 | rootReducer,
25 | initialState,
26 | bindMiddleware([sagaMiddleware])
27 | );
28 |
29 | store.runSagaTask = () => {
30 | store.sagaTask = sagaMiddleware.run(rootSaga);
31 | };
32 |
33 | store.runSagaTask();
34 | return store;
35 | }
36 |
37 | export default configureStore;
38 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const cp = require('child_process');
3 | const { parse } = require('url');
4 | const next = require('next');
5 |
6 | const port = parseInt(process.env.PORT, 10) || 3006;
7 | // 判断开发环境和生产环境
8 | process.env.NODE_ENV = (typeof process.env.NODE_ENV !== 'undefined')
9 | ? process.env.NODE_ENV.trim()
10 | : 'development';
11 |
12 | const dev = process.env.NODE_ENV !== 'production';
13 |
14 | const app = next({ dev });
15 | const handle = app.getRequestHandler();
16 |
17 | app.prepare()
18 | .then(() => {
19 | const server = express();
20 |
21 | server.get('*', (req, res) => {
22 | return handle(req, res);
23 | });
24 |
25 | server.listen(port, (err) => {
26 | if (err) throw err;
27 | const serverUrl = `http:127.0.0.1:${port}`;
28 | console.log(`> Ready on ${serverUrl}`);
29 | // 开发环境自动启动
30 | if (dev) {
31 | switch (process.platform) {
32 | //mac系统使用 一下命令打开url在浏览器
33 | case 'darwin':
34 | cp.exec(`open ${serverUrl}`);
35 | break;
36 | //win系统使用 一下命令打开url在浏览器
37 | case 'win32':
38 | cp.exec(`start ${serverUrl}`);
39 | break;
40 | // 默认mac系统
41 | default:
42 | cp.exec(`open ${serverUrl}`);
43 | }
44 | }
45 | });
46 | });
47 |
48 |
--------------------------------------------------------------------------------
/static/empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/empty.png
--------------------------------------------------------------------------------
/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/favicon.ico
--------------------------------------------------------------------------------
/static/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/logo.png
--------------------------------------------------------------------------------
/static/tags/Algorithm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/Algorithm.png
--------------------------------------------------------------------------------
/static/tags/Angular.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/Angular.png
--------------------------------------------------------------------------------
/static/tags/Back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/Back.png
--------------------------------------------------------------------------------
/static/tags/CSS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/CSS.png
--------------------------------------------------------------------------------
/static/tags/Database.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/Database.png
--------------------------------------------------------------------------------
/static/tags/HTML.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/HTML.png
--------------------------------------------------------------------------------
/static/tags/Http.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/Http.png
--------------------------------------------------------------------------------
/static/tags/Java.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/Java.png
--------------------------------------------------------------------------------
/static/tags/JavaScript.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/JavaScript.png
--------------------------------------------------------------------------------
/static/tags/Nodejs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/Nodejs.png
--------------------------------------------------------------------------------
/static/tags/Product.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/Product.png
--------------------------------------------------------------------------------
/static/tags/Python.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/Python.png
--------------------------------------------------------------------------------
/static/tags/React.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/React.png
--------------------------------------------------------------------------------
/static/tags/Vue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/Vue.png
--------------------------------------------------------------------------------
/static/tags/WEB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/WEB.png
--------------------------------------------------------------------------------
/static/tags/Webpack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/tags/Webpack.png
--------------------------------------------------------------------------------
/static/unknown_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luffyZh/next-markdown-editor/42ae943a30b945d3b52bbdc5bd4fc06ab5884c4c/static/unknown_error.png
--------------------------------------------------------------------------------
/static/users.json:
--------------------------------------------------------------------------------
1 | {
2 | "errcode": 500,
3 | "errmsg": "服务器内部错误",
4 | "data": [
5 | {
6 | "id": 1,
7 | "name": "Leanne Graham",
8 | "username": "Bret",
9 | "email": "Sincere@april.biz",
10 | "address": {
11 | "street": "Kulas Light",
12 | "suite": "Apt. 556",
13 | "city": "Gwenborough",
14 | "zipcode": "92998-3874",
15 | "geo": {
16 | "lat": "-37.3159",
17 | "lng": "81.1496"
18 | }
19 | },
20 | "phone": "1-770-736-8031 x56442",
21 | "website": "hildegard.org",
22 | "company": {
23 | "name": "Romaguera-Crona",
24 | "catchPhrase": "Multi-layered client-server neural-net",
25 | "bs": "harness real-time e-markets"
26 | }
27 | },
28 | {
29 | "id": 2,
30 | "name": "Ervin Howell",
31 | "username": "Antonette",
32 | "email": "Shanna@melissa.tv",
33 | "address": {
34 | "street": "Victor Plains",
35 | "suite": "Suite 879",
36 | "city": "Wisokyburgh",
37 | "zipcode": "90566-7771",
38 | "geo": {
39 | "lat": "-43.9509",
40 | "lng": "-34.4618"
41 | }
42 | },
43 | "phone": "010-692-6593 x09125",
44 | "website": "anastasia.net",
45 | "company": {
46 | "name": "Deckow-Crist",
47 | "catchPhrase": "Proactive didactic contingency",
48 | "bs": "synergize scalable supply-chains"
49 | }
50 | },
51 | {
52 | "id": 3,
53 | "name": "Clementine Bauch",
54 | "username": "Samantha",
55 | "email": "Nathan@yesenia.net",
56 | "address": {
57 | "street": "Douglas Extension",
58 | "suite": "Suite 847",
59 | "city": "McKenziehaven",
60 | "zipcode": "59590-4157",
61 | "geo": {
62 | "lat": "-68.6102",
63 | "lng": "-47.0653"
64 | }
65 | },
66 | "phone": "1-463-123-4447",
67 | "website": "ramiro.info",
68 | "company": {
69 | "name": "Romaguera-Jacobson",
70 | "catchPhrase": "Face to face bifurcated interface",
71 | "bs": "e-enable strategic applications"
72 | }
73 | },
74 | {
75 | "id": 4,
76 | "name": "Patricia Lebsack",
77 | "username": "Karianne",
78 | "email": "Julianne.OConner@kory.org",
79 | "address": {
80 | "street": "Hoeger Mall",
81 | "suite": "Apt. 692",
82 | "city": "South Elvis",
83 | "zipcode": "53919-4257",
84 | "geo": {
85 | "lat": "29.4572",
86 | "lng": "-164.2990"
87 | }
88 | },
89 | "phone": "493-170-9623 x156",
90 | "website": "kale.biz",
91 | "company": {
92 | "name": "Robel-Corkery",
93 | "catchPhrase": "Multi-tiered zero tolerance productivity",
94 | "bs": "transition cutting-edge web services"
95 | }
96 | },
97 | {
98 | "id": 5,
99 | "name": "Chelsey Dietrich",
100 | "username": "Kamren",
101 | "email": "Lucio_Hettinger@annie.ca",
102 | "address": {
103 | "street": "Skiles Walks",
104 | "suite": "Suite 351",
105 | "city": "Roscoeview",
106 | "zipcode": "33263",
107 | "geo": {
108 | "lat": "-31.8129",
109 | "lng": "62.5342"
110 | }
111 | },
112 | "phone": "(254)954-1289",
113 | "website": "demarco.info",
114 | "company": {
115 | "name": "Keebler LLC",
116 | "catchPhrase": "User-centric fault-tolerant solution",
117 | "bs": "revolutionize end-to-end systems"
118 | }
119 | },
120 | {
121 | "id": 6,
122 | "name": "Mrs. Dennis Schulist",
123 | "username": "Leopoldo_Corkery",
124 | "email": "Karley_Dach@jasper.info",
125 | "address": {
126 | "street": "Norberto Crossing",
127 | "suite": "Apt. 950",
128 | "city": "South Christy",
129 | "zipcode": "23505-1337",
130 | "geo": {
131 | "lat": "-71.4197",
132 | "lng": "71.7478"
133 | }
134 | },
135 | "phone": "1-477-935-8478 x6430",
136 | "website": "ola.org",
137 | "company": {
138 | "name": "Considine-Lockman",
139 | "catchPhrase": "Synchronised bottom-line interface",
140 | "bs": "e-enable innovative applications"
141 | }
142 | },
143 | {
144 | "id": 7,
145 | "name": "Kurtis Weissnat",
146 | "username": "Elwyn.Skiles",
147 | "email": "Telly.Hoeger@billy.biz",
148 | "address": {
149 | "street": "Rex Trail",
150 | "suite": "Suite 280",
151 | "city": "Howemouth",
152 | "zipcode": "58804-1099",
153 | "geo": {
154 | "lat": "24.8918",
155 | "lng": "21.8984"
156 | }
157 | },
158 | "phone": "210.067.6132",
159 | "website": "elvis.io",
160 | "company": {
161 | "name": "Johns Group",
162 | "catchPhrase": "Configurable multimedia task-force",
163 | "bs": "generate enterprise e-tailers"
164 | }
165 | },
166 | {
167 | "id": 8,
168 | "name": "Nicholas Runolfsdottir V",
169 | "username": "Maxime_Nienow",
170 | "email": "Sherwood@rosamond.me",
171 | "address": {
172 | "street": "Ellsworth Summit",
173 | "suite": "Suite 729",
174 | "city": "Aliyaview",
175 | "zipcode": "45169",
176 | "geo": {
177 | "lat": "-14.3990",
178 | "lng": "-120.7677"
179 | }
180 | },
181 | "phone": "586.493.6943 x140",
182 | "website": "jacynthe.com",
183 | "company": {
184 | "name": "Abernathy Group",
185 | "catchPhrase": "Implemented secondary concept",
186 | "bs": "e-enable extensible e-tailers"
187 | }
188 | },
189 | {
190 | "id": 9,
191 | "name": "Glenna Reichert",
192 | "username": "Delphine",
193 | "email": "Chaim_McDermott@dana.io",
194 | "address": {
195 | "street": "Dayna Park",
196 | "suite": "Suite 449",
197 | "city": "Bartholomebury",
198 | "zipcode": "76495-3109",
199 | "geo": {
200 | "lat": "24.6463",
201 | "lng": "-168.8889"
202 | }
203 | },
204 | "phone": "(775)976-6794 x41206",
205 | "website": "conrad.com",
206 | "company": {
207 | "name": "Yost and Sons",
208 | "catchPhrase": "Switchable contextually-based project",
209 | "bs": "aggregate real-time technologies"
210 | }
211 | },
212 | {
213 | "id": 10,
214 | "name": "Clementina DuBuque",
215 | "username": "Moriah.Stanton",
216 | "email": "Rey.Padberg@karina.biz",
217 | "address": {
218 | "street": "Kattie Turnpike",
219 | "suite": "Suite 198",
220 | "city": "Lebsackbury",
221 | "zipcode": "31428-2261",
222 | "geo": {
223 | "lat": "-38.2386",
224 | "lng": "57.2232"
225 | }
226 | },
227 | "phone": "024-648-3804",
228 | "website": "ambrose.net",
229 | "company": {
230 | "name": "Hoeger LLC",
231 | "catchPhrase": "Centralized empowering task-force",
232 | "bs": "target end-to-end models"
233 | }
234 | }
235 | ]
236 | }
--------------------------------------------------------------------------------