1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-25 12:56:41 +07:00

added markdown formatter

This commit is contained in:
Fedor Katurov 2021-02-24 14:18:59 +07:00
parent 8f9c61e1f6
commit 0666237586
7 changed files with 111 additions and 126 deletions

View file

@ -9,7 +9,7 @@ const CommentTextBlock: FC<IProps> = ({ block }) => {
<div
className={styles.text}
dangerouslySetInnerHTML={{
__html: `<p>${block.content}</p>`,
__html: block.content,
}}
/>
);

View file

@ -8,6 +8,17 @@ import Axios from 'axios';
import { PRESETS } from '~/constants/urls';
import { COMMENT_BLOCK_DETECTORS, COMMENT_BLOCK_TYPES, ICommentBlock } from '~/constants/comment';
import format from 'date-fns/format';
import { pipe } from 'ramda';
import {
formatDash,
formatExclamations,
formatMarkdown,
formatTextClickableUsernames,
formatTextComments,
formatTextSanitizeTags,
formatTextSanitizeYoutube,
formatTextTodos,
} from '~/utils/formatText';
export const getStyle = (oElm: any, strCssRule: string) => {
if (document.defaultView && document.defaultView.getComputedStyle) {
@ -82,50 +93,18 @@ export const getURL = (file: Partial<IFile>, size?: typeof PRESETS[keyof typeof
return file?.url ? getURLFromString(file.url, size) : null;
};
export const formatText = (text: string): string =>
!text
? ''
: text
.replace(
/(https?:\/\/(www\.)?(youtube\.com|youtu\.be)\/(watch)?(\?v=)?[\w\-\&\=]+)/gim,
'\n$1\n'
)
.replace(/\n{1,}/gim, '\n')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(
/~([\wа-яА-Я-]+)/giu,
'<span class="username" onClick="window.postMessage({ type: \'username\', username: \'$1\'});">~$1</span>'
)
.replace(/:\/\//gim, ':|--|')
.replace(/(\/\/[^\n]+)/gim, '<span class="grey">$1</span>')
.replace(/\/\/\s*(todo|туду):?\s*([^\n]+)/gim, '// <span class="todo">$1</span> $2')
.replace(
/\/\/\s*(done|сделано|сделал|готово|fixed|пофикшено|фиксед):?\s*([^\n]+)/gim,
'// <span class="done">$1</span> $2'
)
.replace(/(\*\*[\s\S]*?\*\*)/gim, '<b class="bold white">$1</b>')
.replace(/(\_\_[\s\S]*?\_\_)/gim, '<i>$1</i>')
.replace(/(\!\![\s\S]*?(\!\!|\n|$))/gim, '<span class="green">$1</span>')
.replace(/(\/\*[\s\S]*?\*\/)/gim, '<span class="grey">$1</span>')
.replace(/([=|-]{5,})/gim, '<hr />')
.replace(/:\|--\|/gim, '://')
.replace(
/(\b(https?|ftp|file):\/\/([-A-Z0-9+&@#%?=~_|!:,.;]*)([-A-Z0-9+&@#%?\/=~_|!:,.;]*)[-A-Z0-9+&@#\/%=~_|])/gi,
'<a href="$1" target="blank" rel="nofollow">$1</a>'
)
.replace(' -- ', ' — ')
.split('\n')
.filter(el => el.trim().length)
.join('\n');
export const formatText = pipe(
formatTextSanitizeYoutube,
formatTextSanitizeTags,
formatTextClickableUsernames,
formatTextComments,
formatTextTodos,
formatExclamations,
formatDash,
formatMarkdown
);
export const formatTextParagraphs = (text: string): string =>
(text &&
formatText(text)
.split('\n')
.map(str => `<p>${str}</p>`)
.join('\n')) ||
null;
export const formatTextParagraphs = (text: string): string => (text && formatText(text)) || null;
export const findBlockType = (line: string): ValueOf<typeof COMMENT_BLOCK_TYPES> => {
const match = Object.values(COMMENT_BLOCK_DETECTORS).find(detector => line.match(detector.test));

71
src/utils/formatText.ts Normal file
View file

@ -0,0 +1,71 @@
import marked from 'marked';
/**
* Cleans youtube urls
*/
export const formatTextSanitizeYoutube = (text: string): string =>
text.replace(
/(https?:\/\/(www\.)?(youtube\.com|youtu\.be)\/(watch)?(\?v=)?[\w\-\&\=]+)/gim,
'\n$1\n'
);
/**
* Removes HTML tags
*/
export const formatTextSanitizeTags = (text: string): string =>
text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
/**
* Returns clickable usernames
*/
export const formatTextClickableUsernames = (text: string): string =>
text.replace(
/~([\wа-яА-Я-]+)/giu,
'<span class="username" onClick="window.postMessage({ type: \'username\', username: \'$1\'});">~$1</span>'
);
/**
* Makes gray comments
*/
export const formatTextComments = (text: string): string =>
text
.replace(/:\/\//gim, ':|--|')
.replace(/(\/\/[^\n]+)/gim, '<span class="grey">$1</span>')
.replace(/(\/\*[\s\S]*?\*\/)/gim, '<span class="grey">$1</span>')
.replace(/:\|--\|/gim, '://');
/**
* Highlights todos
*/
export const formatTextTodos = (text: string): string =>
text
.replace(/\/\/\s*(todo|туду):?\s*([^\n]+)/gim, '// <span class="todo">$1</span> $2')
.replace(
/\/\/\s*(done|сделано|сделал|готово|fixed|пофикшено|фиксед):?\s*([^\n]+)/gim,
'// <span class="done">$1</span> $2'
);
/**
* Formats !!exclamation messages with green color
*/
export const formatExclamations = (text: string): string =>
text.replace(/(\!\![\s\S]*?(\!\!|\n|$))/gim, '<span class="green">$1</span>');
/**
* Formats links
*/
export const formatLinks = (text: string): string =>
text.replace(
/(\b(https?|ftp|file):\/\/([-A-Z0-9+&@#%?=~_|!:,.;]*)([-A-Z0-9+&@#%?\/=~_|!:,.;]*)[-A-Z0-9+&@#\/%=~_|])/gi,
'<a href="$1" target="blank" rel="nofollow">$1</a>'
);
/**
* Replaces -- with dash
*/
export const formatDash = (text: string): string => text.replace(' -- ', ' — ');
/**
* Formats with markdown
*/
export const formatMarkdown = (text: string): string => marked(text);

View file

@ -5,11 +5,5 @@ type Handlers<State, Types extends string, Actions extends Action<Types>> = {
readonly [Type in Types]: (state: State, action: Actions) => State;
};
// export const createReducer = <State, Types extends string, Actions extends Action<Types>>(
// initialState: State,
// handlers: Handlers<State, Types, Actions>,
// ) => (state = initialState, action: Actions) =>
// handlers.hasOwnProperty(action.type) ? handlers[action.type as Types](state, action) : state;
export const createReducer = (initialState, handlers) => (state = initialState, action) =>
handlers.hasOwnProperty(action.type) ? handlers[action.type](state, action) : state;