markdown fixes - blockquotes and embedded videos

This commit is contained in:
zeppi 2022-02-14 17:35:14 -05:00 committed by jessopb
parent c553ee46f6
commit a574a5c1de
6 changed files with 127 additions and 43 deletions

View file

@ -1,24 +1,24 @@
// @flow // @flow
import * as React from 'react'; import { CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS } from 'config';
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 { formattedLinks, inlineLinks } from 'util/remark-lbry'; import { formattedLinks, inlineLinks } from 'util/remark-lbry';
import { formattedTimestamp, inlineTimestamp } from 'util/remark-timestamp'; import { formattedTimestamp, inlineTimestamp } from 'util/remark-timestamp';
import { formattedEmote, inlineEmote } from 'util/remark-emote'; 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 * 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 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-]+:/; const RE_EMOTE = /:\+1:|:-1:|:[\w-]+:/;
@ -171,17 +171,20 @@ const MarkdownPreview = (props: MarkdownProps) => {
} catch (e) {} } catch (e) {}
if (lbrySrc && lbrySrc.startsWith('lbry://')) { if (lbrySrc && lbrySrc.startsWith('lbry://')) {
console.log('lbrysrc', lbrySrc);
return lbrySrc; return lbrySrc;
} }
//
// if (lbrySrc && lbrySrc.startsWith('https://odysee.com')) {
// console.log('lbrysrc', lbrySrc)
// return lbrySrc;
// }
// console.log('iframeh', iframeHtml)
return 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 = { const remarkOptions: Object = {
sanitize: schema, sanitize: schema,
fragment: React.Fragment, fragment: React.Fragment,
@ -216,22 +219,10 @@ const MarkdownPreview = (props: MarkdownProps) => {
}; };
// Strip all content and just render text // Strip all content and just render text
if (strip || stripQuote) { if (strip) {
// Remove new lines and extra space // Remove new lines and extra space
remarkOptions.remarkReactComponents.p = SimpleText; remarkOptions.remarkReactComponents.p = SimpleText;
return stripQuote ? ( return (
<span dir="auto" className="markdown-preview">
<blockquote>
{
remark()
.use(remarkStrip)
.use(remarkFrontMatter, ['yaml'])
.use(reactRenderer, remarkOptions)
.processSync(content).contents
}
</blockquote>
</span>
) : (
<span dir="auto" className="markdown-preview"> <span dir="auto" className="markdown-preview">
{ {
remark() remark()

View file

@ -24,6 +24,7 @@ import PdfViewer from 'component/viewers/pdfViewer';
type Props = { type Props = {
uri: string, uri: string,
streamingUrl: string, streamingUrl: string,
embedded?: boolean,
contentType: string, contentType: string,
claim: StreamClaim, claim: StreamClaim,
currentTheme: string, currentTheme: string,
@ -44,8 +45,9 @@ class FileRender extends React.PureComponent<Props> {
} }
componentDidMount() { componentDidMount() {
const { embedded } = this.props;
window.addEventListener('keydown', this.escapeListener, true); window.addEventListener('keydown', this.escapeListener, true);
analytics.playerLoadedEvent(); analytics.playerLoadedEvent(embedded);
} }
componentWillUnmount() { componentWillUnmount() {
@ -144,12 +146,13 @@ class FileRender extends React.PureComponent<Props> {
} }
render() { render() {
const { renderMode, className } = this.props; const { embedded, renderMode, className } = this.props;
return ( return (
<div <div
className={classnames('file-render', className, { className={classnames('file-render', className, {
'file-render--document': RENDER_MODES.TEXT_MODES.includes(renderMode), 'file-render--document': RENDER_MODES.TEXT_MODES.includes(renderMode),
'file-render--embed': embedded,
'file-render--video': renderMode === RENDER_MODES.VIDEO || renderMode === RENDER_MODES.AUDIO, 'file-render--video': renderMode === RENDER_MODES.VIDEO || renderMode === RENDER_MODES.AUDIO,
})} })}
> >

View file

@ -69,3 +69,4 @@
@import 'component/swipe-list'; @import 'component/swipe-list';
@import 'component/utils'; @import 'component/utils';
@import 'component/settings'; @import 'component/settings';
@import 'component/embed-player';

View 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;
}

View file

@ -12,13 +12,19 @@ const invalidRegex = /[-_.+=?!@#$%^&*:;,{}<>\w/\\]/;
const mentionRegex = /@[^\s()"-_.+=?!@$%^&*;,{}<>/\\]*/gm; const mentionRegex = /@[^\s()"-_.+=?!@$%^&*;,{}<>/\\]*/gm;
function handlePunctuation(value) { function handlePunctuation(value) {
const modifierIndex = const protocolIndex = value.indexOf('lbry://') === 0 ? protocol.length - 1 : 0;
(value.indexOf(':') >= 0 && value.indexOf(':')) || (value.indexOf('#') >= 0 && value.indexOf('#')); 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; let punctuationIndex;
punctuationMarks.some((p) => { punctuationMarks.some((p) => {
if (modifierIndex) { if (claimModifierIndex) {
punctuationIndex = value.indexOf(p, modifierIndex + 1) >= 0 && value.indexOf(p, modifierIndex + 1); punctuationIndex = value.indexOf(p, claimModifierIndex + 1) >= 0 && value.indexOf(p, claimModifierIndex + 1);
} }
return punctuationIndex; return punctuationIndex;
}); });
@ -108,15 +114,15 @@ function tokenizeURI(eat, value, silent) {
// Configure tokenizer for lbry urls // Configure tokenizer for lbry urls
tokenizeURI.locator = locateURI; tokenizeURI.locator = locateURI;
tokenizeURI.notInList = true; tokenizeURI.notInList = false;
tokenizeURI.notInLink = true; tokenizeURI.notInLink = true;
tokenizeURI.notInBlock = true; tokenizeURI.notInBlock = false;
// Configure tokenizer for lbry channels // Configure tokenizer for lbry channels
tokenizeMention.locator = locateMention; tokenizeMention.locator = locateMention;
tokenizeMention.notInList = true; tokenizeMention.notInList = false;
tokenizeMention.notInLink = true; tokenizeMention.notInLink = true;
tokenizeMention.notInBlock = true; tokenizeMention.notInBlock = false;
const visitor = (node, index, parent) => { const visitor = (node, index, parent) => {
if (node.type === 'link' && parent && parent.type === 'paragraph') { if (node.type === 'link' && parent && parent.type === 'paragraph') {

View 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;