commit
2f0a5a043e
@ -8,7 +8,7 @@
|
|||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta name="description" content="Fast nostr web ui" />
|
<meta name="description" content="Fast nostr web ui" />
|
||||||
<meta http-equiv="Content-Security-Policy"
|
<meta http-equiv="Content-Security-Policy"
|
||||||
content="default-src 'self'; child-src 'none'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; connect-src wss://* 'self' https://*; img-src * data:; font-src https://fonts.gstatic.com; media-src *; script-src 'self' https://static.cloudflareinsights.com;" />
|
content="default-src 'self'; child-src 'none'; frame-src youtube.com www.youtube.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; connect-src wss://* 'self' https://*; img-src * data:; font-src https://fonts.gstatic.com; media-src *; script-src 'self' https://static.cloudflareinsights.com;" />
|
||||||
|
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/nostrich_512.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/nostrich_512.png" />
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
|
@ -56,4 +56,9 @@ export const MentionRegex = /(#\[\d+\])/gi;
|
|||||||
/**
|
/**
|
||||||
* Simple lightning invoice regex
|
* Simple lightning invoice regex
|
||||||
*/
|
*/
|
||||||
export const InvoiceRegex = /(lnbc\w+)/i;
|
export const InvoiceRegex = /(lnbc\w+)/i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* YouTube URL regex
|
||||||
|
*/
|
||||||
|
export const YoutubeUrlRegex = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/
|
||||||
|
78
src/Text.js
78
src/Text.js
@ -1,41 +1,63 @@
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
import Invoice from "./element/Invoice";
|
import Invoice from "./element/Invoice";
|
||||||
import { UrlRegex, FileExtensionRegex, MentionRegex, InvoiceRegex } from "./Const";
|
import { UrlRegex, FileExtensionRegex, MentionRegex, InvoiceRegex, YoutubeUrlRegex } from "./Const";
|
||||||
import { eventLink, profileLink } from "./Util";
|
import { eventLink, profileLink } from "./Util";
|
||||||
|
|
||||||
|
function transformHttpLink(a) {
|
||||||
|
try {
|
||||||
|
const url = new URL(a);
|
||||||
|
const vParam = url.searchParams.get('v')
|
||||||
|
const youtubeId = YoutubeUrlRegex.test(a) && RegExp.$1
|
||||||
|
const extension = FileExtensionRegex.test(url.pathname.toLowerCase()) && RegExp.$1
|
||||||
|
if (extension) {
|
||||||
|
switch (extension) {
|
||||||
|
case "gif":
|
||||||
|
case "jpg":
|
||||||
|
case "jpeg":
|
||||||
|
case "png":
|
||||||
|
case "bmp":
|
||||||
|
case "webp": {
|
||||||
|
return <img key={url} src={url} />;
|
||||||
|
}
|
||||||
|
case "mp4":
|
||||||
|
case "mov":
|
||||||
|
case "mkv":
|
||||||
|
case "avi":
|
||||||
|
case "m4v": {
|
||||||
|
return <video key={url} src={url} controls />
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return <a key={url} href={url}>{url.toString()}</a>
|
||||||
|
}
|
||||||
|
} else if (youtubeId) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<br />
|
||||||
|
<iframe
|
||||||
|
src={`https://www.youtube.com/embed/${youtubeId}`}
|
||||||
|
title="YouTube video player"
|
||||||
|
frameborder="0"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||||
|
allowfullscreen=""
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return <a key={url} href={url}>{url.toString()}</a>
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(`Not a valid url: ${a}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function extractLinks(fragments) {
|
export function extractLinks(fragments) {
|
||||||
return fragments.map(f => {
|
return fragments.map(f => {
|
||||||
if (typeof f === "string") {
|
if (typeof f === "string") {
|
||||||
return f.split(UrlRegex).map(a => {
|
return f.split(UrlRegex).map(a => {
|
||||||
if (a.startsWith("http")) {
|
if (a.startsWith("http")) {
|
||||||
try {
|
return transformHttpLink(a)
|
||||||
let url = new URL(a);
|
|
||||||
let ext = url.pathname.toLowerCase().match(FileExtensionRegex);
|
|
||||||
if (ext) {
|
|
||||||
switch (ext[1]) {
|
|
||||||
case "gif":
|
|
||||||
case "jpg":
|
|
||||||
case "jpeg":
|
|
||||||
case "png":
|
|
||||||
case "bmp":
|
|
||||||
case "webp": {
|
|
||||||
return <img key={url} src={url} />;
|
|
||||||
}
|
|
||||||
case "mp4":
|
|
||||||
case "mov":
|
|
||||||
case "mkv":
|
|
||||||
case "avi":
|
|
||||||
case "m4v": {
|
|
||||||
return <video key={url} src={url} controls />
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return <a key={url} href={url}>{url.toString()}</a>
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(`Not a valid url: ${a}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
});
|
});
|
||||||
|
@ -22,11 +22,15 @@
|
|||||||
word-break: normal;
|
word-break: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note > .body > img, .note > .body > video {
|
.note > .body > img, .note > .body > video, .note > .body > iframe {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.note > .body > iframe {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.note > .header > img:hover, .note > .header > .name > .reply:hover, .note > .body:hover {
|
.note > .header > img:hover, .note > .header > .name > .reply:hover, .note > .body:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import { useEffect, useState } from "react";
|
|||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import * as secp from '@noble/secp256k1';
|
import * as secp from '@noble/secp256k1';
|
||||||
import { bech32 } from "bech32";
|
|
||||||
|
|
||||||
import { setPrivateKey, setPublicKey } from "../state/Login";
|
import { setPrivateKey, setPublicKey } from "../state/Login";
|
||||||
import { EmailRegex } from "../Const";
|
import { EmailRegex } from "../Const";
|
||||||
|
Loading…
Reference in New Issue
Block a user