Added code highlighting
This commit is contained in:
@ -75,6 +75,7 @@
|
|||||||
"exports-loader": "^0.6.3",
|
"exports-loader": "^0.6.3",
|
||||||
"file-loader": "^0.8.5",
|
"file-loader": "^0.8.5",
|
||||||
"fsevents": "^1.0.11",
|
"fsevents": "^1.0.11",
|
||||||
|
"highlight.js": "^9.4.0",
|
||||||
"history": "^1.17.0",
|
"history": "^1.17.0",
|
||||||
"imports-loader": "^0.6.5",
|
"imports-loader": "^0.6.5",
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
|
@ -2,6 +2,10 @@ import {
|
|||||||
DataTypes,
|
DataTypes,
|
||||||
sequelize,
|
sequelize,
|
||||||
} from '../sequelize';
|
} from '../sequelize';
|
||||||
|
import {
|
||||||
|
convertToMarkdown,
|
||||||
|
truncateMarkdown,
|
||||||
|
} from '../utils/markdown';
|
||||||
import Atlas from './Atlas';
|
import Atlas from './Atlas';
|
||||||
import Team from './Team';
|
import Team from './Team';
|
||||||
import User from './User';
|
import User from './User';
|
||||||
@ -10,6 +14,15 @@ const Document = sequelize.define('document', {
|
|||||||
id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true },
|
id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true },
|
||||||
title: DataTypes.STRING,
|
title: DataTypes.STRING,
|
||||||
text: DataTypes.TEXT,
|
text: DataTypes.TEXT,
|
||||||
|
html: DataTypes.TEXT,
|
||||||
|
preview: DataTypes.TEXT,
|
||||||
|
}, {
|
||||||
|
hooks: {
|
||||||
|
beforeCreate: (doc) => {
|
||||||
|
doc.html = convertToMarkdown(doc.text);
|
||||||
|
doc.preview = truncateMarkdown(doc.text, 160);
|
||||||
|
},
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Document.belongsTo(Atlas, { as: 'atlas' });
|
Document.belongsTo(Atlas, { as: 'atlas' });
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import marked from 'marked';
|
|
||||||
import { truncateMarkdown } from './utils/truncate';
|
|
||||||
|
|
||||||
import Document from './models/Document';
|
import Document from './models/Document';
|
||||||
|
|
||||||
export function presentUser(user) {
|
export function presentUser(user) {
|
||||||
@ -60,8 +57,8 @@ export async function presentDocument(document, includeAtlas=false) {
|
|||||||
id: document.id,
|
id: document.id,
|
||||||
title: document.title,
|
title: document.title,
|
||||||
text: document.text,
|
text: document.text,
|
||||||
html: marked(document.text),
|
html: document.html,
|
||||||
preview: truncateMarkdown(document.text, 160),
|
preview: document.preview,
|
||||||
createdAt: document.createdAt,
|
createdAt: document.createdAt,
|
||||||
updatedAt: document.updatedAt,
|
updatedAt: document.updatedAt,
|
||||||
atlas: document.atlaId,
|
atlas: document.atlaId,
|
||||||
|
45
server/utils/markdown.js
Normal file
45
server/utils/markdown.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import truncate from 'truncate-html';
|
||||||
|
import marked, { Renderer } from 'marked';
|
||||||
|
import highlight from 'highlight.js';
|
||||||
|
|
||||||
|
const renderer = new Renderer();
|
||||||
|
renderer.code = (code, language) => {
|
||||||
|
const validLang = !!(language && highlight.getLanguage(language));
|
||||||
|
const highlighted = validLang ? highlight.highlight(language, code).value : code;
|
||||||
|
return `<pre><code class="hljs ${language}">${highlighted}</code></pre>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
marked.setOptions({
|
||||||
|
renderer: renderer,
|
||||||
|
gfm: true,
|
||||||
|
tables: true,
|
||||||
|
breaks: false,
|
||||||
|
pedantic: false,
|
||||||
|
sanitize: true,
|
||||||
|
smartLists: true,
|
||||||
|
smartypants: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: This is syncronous and can be costly,
|
||||||
|
// should be performed outside http request
|
||||||
|
const convertToMarkdown = (text) => {
|
||||||
|
return marked(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
truncate.defaultOptions = {
|
||||||
|
stripTags: false,
|
||||||
|
ellipsis: '...',
|
||||||
|
decodeEntities: false,
|
||||||
|
excludes: ['h1', 'pre', ],
|
||||||
|
};
|
||||||
|
|
||||||
|
const truncateMarkdown = (text, length) => {
|
||||||
|
const html = convertToMarkdown(text);
|
||||||
|
return truncate(html, length);
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
convertToMarkdown,
|
||||||
|
truncateMarkdown,
|
||||||
|
};
|
@ -1,18 +0,0 @@
|
|||||||
import truncate from 'truncate-html';
|
|
||||||
import marked from 'marked';
|
|
||||||
|
|
||||||
truncate.defaultOptions = {
|
|
||||||
stripTags: false,
|
|
||||||
ellipsis: '...',
|
|
||||||
decodeEntities: false,
|
|
||||||
excludes: ['h1', 'pre',],
|
|
||||||
};
|
|
||||||
|
|
||||||
const truncateMarkdown = (text, length) => {
|
|
||||||
const html = marked(text);
|
|
||||||
return truncate(html, length);
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
truncateMarkdown
|
|
||||||
};
|
|
73
src/assets/styles/github-gist.scss
Normal file
73
src/assets/styles/github-gist.scss
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
:global {
|
||||||
|
/**
|
||||||
|
* GitHub Gist Theme
|
||||||
|
* Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
background: white;
|
||||||
|
padding: 0.5em;
|
||||||
|
color: #333333;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-meta {
|
||||||
|
color: #969896;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-strong,
|
||||||
|
.hljs-emphasis,
|
||||||
|
.hljs-quote {
|
||||||
|
color: #df5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
.hljs-type {
|
||||||
|
color: #a71d5d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-symbol,
|
||||||
|
.hljs-bullet,
|
||||||
|
.hljs-attribute {
|
||||||
|
color: #0086b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-section,
|
||||||
|
.hljs-name {
|
||||||
|
color: #63a35c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-tag {
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-attr,
|
||||||
|
.hljs-selector-id,
|
||||||
|
.hljs-selector-class,
|
||||||
|
.hljs-selector-attr,
|
||||||
|
.hljs-selector-pseudo {
|
||||||
|
color: #795da3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
color: #55a532;
|
||||||
|
background-color: #eaffea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
color: #bd2c00;
|
||||||
|
background-color: #ffecec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-link {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,7 @@ const CenteredContent = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
CenteredContent.defaultProps = {
|
CenteredContent.defaultProps = {
|
||||||
maxWidth: '600px',
|
maxWidth: '740px',
|
||||||
};
|
};
|
||||||
|
|
||||||
CenteredContent.propTypes = {
|
CenteredContent.propTypes = {
|
||||||
|
@ -18,6 +18,7 @@ import reducers from 'reducers';
|
|||||||
import 'normalize.css/normalize.css';
|
import 'normalize.css/normalize.css';
|
||||||
import 'utils/base-styles.scss';
|
import 'utils/base-styles.scss';
|
||||||
import 'fonts/atlas/atlas.css';
|
import 'fonts/atlas/atlas.css';
|
||||||
|
import 'assets/styles/github-gist.scss';
|
||||||
|
|
||||||
import Home from 'scenes/Home';
|
import Home from 'scenes/Home';
|
||||||
import Editor from 'scenes/Editor';
|
import Editor from 'scenes/Editor';
|
||||||
|
@ -85,3 +85,11 @@ hr {
|
|||||||
border-bottom-style: solid;
|
border-bottom-style: solid;
|
||||||
border-bottom-color: #ccc;
|
border-bottom-color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.hljs {
|
||||||
|
border: 1px solid rgba(0,0,0,.0625);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user