markdown fixes - blockquotes and embedded videos
This commit is contained in:
parent
c553ee46f6
commit
a574a5c1de
6 changed files with 127 additions and 43 deletions
|
@ -1,24 +1,24 @@
|
|||
// @flow
|
||||
import * as React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import remark from 'remark';
|
||||
import remarkAttr from 'remark-attr';
|
||||
import remarkStrip from 'strip-markdown';
|
||||
import remarkEmoji from 'remark-emoji';
|
||||
import remarkBreaks from 'remark-breaks';
|
||||
import remarkFrontMatter from 'remark-frontmatter';
|
||||
import reactRenderer from 'remark-react';
|
||||
import MarkdownLink from 'component/markdownLink';
|
||||
import defaultSchema from 'hast-util-sanitize/lib/github.json';
|
||||
import { CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS } from 'config';
|
||||
import { formattedLinks, inlineLinks } from 'util/remark-lbry';
|
||||
import { formattedTimestamp, inlineTimestamp } from 'util/remark-timestamp';
|
||||
import { formattedEmote, inlineEmote } from 'util/remark-emote';
|
||||
import ZoomableImage from 'component/zoomableImage';
|
||||
import { CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS } from 'config';
|
||||
import Button from 'component/button';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import { parse } from 'node-html-parser';
|
||||
import * as React from 'react';
|
||||
import Button from 'component/button';
|
||||
import classnames from 'classnames';
|
||||
import defaultSchema from 'hast-util-sanitize/lib/github.json';
|
||||
import MarkdownLink from 'component/markdownLink';
|
||||
import OptimizedImage from 'component/optimizedImage';
|
||||
import reactRenderer from 'remark-react';
|
||||
import remark from 'remark';
|
||||
import remarkAttr from 'remark-attr';
|
||||
import remarkBreaks from 'remark-breaks';
|
||||
import remarkEmoji from 'remark-emoji';
|
||||
import remarkFrontMatter from 'remark-frontmatter';
|
||||
import remarkStrip from 'strip-markdown';
|
||||
import ZoomableImage from 'component/zoomableImage';
|
||||
import { parse } from 'node-html-parser';
|
||||
|
||||
const RE_EMOTE = /:\+1:|:-1:|:[\w-]+:/;
|
||||
|
||||
|
@ -171,17 +171,20 @@ const MarkdownPreview = (props: MarkdownProps) => {
|
|||
} catch (e) {}
|
||||
|
||||
if (lbrySrc && lbrySrc.startsWith('lbry://')) {
|
||||
console.log('lbrysrc', lbrySrc);
|
||||
return lbrySrc;
|
||||
}
|
||||
//
|
||||
// if (lbrySrc && lbrySrc.startsWith('https://odysee.com')) {
|
||||
// console.log('lbrysrc', lbrySrc)
|
||||
// return lbrySrc;
|
||||
// }
|
||||
// console.log('iframeh', iframeHtml)
|
||||
|
||||
return iframeHtml;
|
||||
})
|
||||
: '';
|
||||
|
||||
const initialQuote = strippedContent.split(' ').find((word) => word.length > 0 || word.charAt(0) === '>');
|
||||
let stripQuote;
|
||||
if (initialQuote && initialQuote.charAt(0) === '>') stripQuote = true;
|
||||
|
||||
const remarkOptions: Object = {
|
||||
sanitize: schema,
|
||||
fragment: React.Fragment,
|
||||
|
@ -216,22 +219,10 @@ const MarkdownPreview = (props: MarkdownProps) => {
|
|||
};
|
||||
|
||||
// Strip all content and just render text
|
||||
if (strip || stripQuote) {
|
||||
if (strip) {
|
||||
// Remove new lines and extra space
|
||||
remarkOptions.remarkReactComponents.p = SimpleText;
|
||||
return stripQuote ? (
|
||||
<span dir="auto" className="markdown-preview">
|
||||
<blockquote>
|
||||
{
|
||||
remark()
|
||||
.use(remarkStrip)
|
||||
.use(remarkFrontMatter, ['yaml'])
|
||||
.use(reactRenderer, remarkOptions)
|
||||
.processSync(content).contents
|
||||
}
|
||||
</blockquote>
|
||||
</span>
|
||||
) : (
|
||||
return (
|
||||
<span dir="auto" className="markdown-preview">
|
||||
{
|
||||
remark()
|
||||
|
|
|
@ -24,6 +24,7 @@ import PdfViewer from 'component/viewers/pdfViewer';
|
|||
type Props = {
|
||||
uri: string,
|
||||
streamingUrl: string,
|
||||
embedded?: boolean,
|
||||
contentType: string,
|
||||
claim: StreamClaim,
|
||||
currentTheme: string,
|
||||
|
@ -44,8 +45,9 @@ class FileRender extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { embedded } = this.props;
|
||||
window.addEventListener('keydown', this.escapeListener, true);
|
||||
analytics.playerLoadedEvent();
|
||||
analytics.playerLoadedEvent(embedded);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -144,12 +146,13 @@ class FileRender extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { renderMode, className } = this.props;
|
||||
const { embedded, renderMode, className } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('file-render', className, {
|
||||
'file-render--document': RENDER_MODES.TEXT_MODES.includes(renderMode),
|
||||
'file-render--embed': embedded,
|
||||
'file-render--video': renderMode === RENDER_MODES.VIDEO || renderMode === RENDER_MODES.AUDIO,
|
||||
})}
|
||||
>
|
||||
|
|
|
@ -69,3 +69,4 @@
|
|||
@import 'component/swipe-list';
|
||||
@import 'component/utils';
|
||||
@import 'component/settings';
|
||||
@import 'component/embed-player';
|
||||
|
|
67
ui/scss/component/_embed-player.scss
Normal file
67
ui/scss/component/_embed-player.scss
Normal file
|
@ -0,0 +1,67 @@
|
|||
.embed__wrapper {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: var(--color-black);
|
||||
}
|
||||
|
||||
.embed__wrapper--light-background {
|
||||
@extend .embed__wrapper;
|
||||
|
||||
.vjs-poster,
|
||||
video {
|
||||
background-color: var(--color-white);
|
||||
}
|
||||
}
|
||||
|
||||
.embed__inline-button {
|
||||
@include thumbnail;
|
||||
position: relative;
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100%;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-top-right-radius: var(--border-radius);
|
||||
background-color: var(--color-black);
|
||||
|
||||
@media (max-width: $breakpoint-small) {
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.embed__inline-button-preview {
|
||||
@extend .embed__inline-button;
|
||||
background-color: var(--color-editor-inline-code-bg);
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.embed__loading {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.embed__loading-text {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--color-white);
|
||||
|
||||
h1 {
|
||||
font-size: var(--font-large);
|
||||
}
|
||||
}
|
||||
|
||||
.embed__overlay-logo {
|
||||
max-height: 2rem;
|
||||
max-width: 7rem;
|
||||
}
|
|
@ -12,13 +12,19 @@ const invalidRegex = /[-_.+=?!@#$%^&*:;,{}<>\w/\\]/;
|
|||
const mentionRegex = /@[^\s()"-_.+=?!@$%^&*;,{}<>/\\]*/gm;
|
||||
|
||||
function handlePunctuation(value) {
|
||||
const modifierIndex =
|
||||
(value.indexOf(':') >= 0 && value.indexOf(':')) || (value.indexOf('#') >= 0 && value.indexOf('#'));
|
||||
const protocolIndex = value.indexOf('lbry://') === 0 ? protocol.length - 1 : 0;
|
||||
const channelModifierIndex =
|
||||
(value.indexOf(':', protocolIndex) >= 0 && value.indexOf(':', protocolIndex)) ||
|
||||
(value.indexOf('#', protocolIndex) >= 0 && value.indexOf('#', protocolIndex));
|
||||
const claimModifierIndex =
|
||||
(value.indexOf(':', channelModifierIndex + 1) >= 0 && value.indexOf(':', channelModifierIndex + 1)) ||
|
||||
(value.indexOf('#', channelModifierIndex + 1) >= 0 && value.indexOf('#', channelModifierIndex + 1)) ||
|
||||
channelModifierIndex;
|
||||
|
||||
let punctuationIndex;
|
||||
punctuationMarks.some((p) => {
|
||||
if (modifierIndex) {
|
||||
punctuationIndex = value.indexOf(p, modifierIndex + 1) >= 0 && value.indexOf(p, modifierIndex + 1);
|
||||
if (claimModifierIndex) {
|
||||
punctuationIndex = value.indexOf(p, claimModifierIndex + 1) >= 0 && value.indexOf(p, claimModifierIndex + 1);
|
||||
}
|
||||
return punctuationIndex;
|
||||
});
|
||||
|
@ -108,15 +114,15 @@ function tokenizeURI(eat, value, silent) {
|
|||
|
||||
// Configure tokenizer for lbry urls
|
||||
tokenizeURI.locator = locateURI;
|
||||
tokenizeURI.notInList = true;
|
||||
tokenizeURI.notInList = false;
|
||||
tokenizeURI.notInLink = true;
|
||||
tokenizeURI.notInBlock = true;
|
||||
tokenizeURI.notInBlock = false;
|
||||
|
||||
// Configure tokenizer for lbry channels
|
||||
tokenizeMention.locator = locateMention;
|
||||
tokenizeMention.notInList = true;
|
||||
tokenizeMention.notInList = false;
|
||||
tokenizeMention.notInLink = true;
|
||||
tokenizeMention.notInBlock = true;
|
||||
tokenizeMention.notInBlock = false;
|
||||
|
||||
const visitor = (node, index, parent) => {
|
||||
if (node.type === 'link' && parent && parent.type === 'paragraph') {
|
||||
|
|
16
web/middleware/iframe-destroyer.js
Normal file
16
web/middleware/iframe-destroyer.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
const PAGES = require('../../ui/constants/pages');
|
||||
|
||||
async function iframeDestroyerMiddleware(ctx, next) {
|
||||
const {
|
||||
request: { path },
|
||||
} = ctx;
|
||||
const decodedPath = decodeURIComponent(path);
|
||||
|
||||
if (!decodedPath.startsWith(`/$/${PAGES.EMBED}`)) {
|
||||
ctx.set('X-Frame-Options', 'DENY');
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
module.exports = iframeDestroyerMiddleware;
|
Loading…
Reference in a new issue