commit
85a65580f2
@ -62,3 +62,8 @@ export const InvoiceRegex = /(lnbc\w+)/i;
|
||||
* YouTube URL regex
|
||||
*/
|
||||
export const YoutubeUrlRegex = /^(?:https?:\/\/)?(?:www|m\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/
|
||||
|
||||
/**
|
||||
* Hashtag regex
|
||||
*/
|
||||
export const HashtagRegex = /(#[a-z\d-]+)/ig
|
||||
|
18
src/Text.js
18
src/Text.js
@ -1,9 +1,10 @@
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import Invoice from "./element/Invoice";
|
||||
import { UrlRegex, FileExtensionRegex, MentionRegex, InvoiceRegex, YoutubeUrlRegex } from "./Const";
|
||||
import { UrlRegex, FileExtensionRegex, MentionRegex, InvoiceRegex, YoutubeUrlRegex, HashtagRegex } from "./Const";
|
||||
import { eventLink, hexToBech32, profileLink } from "./Util";
|
||||
import LazyImage from "./element/LazyImage";
|
||||
import Hashtag from "./element/Hashtag";
|
||||
|
||||
function transformHttpLink(a) {
|
||||
try {
|
||||
@ -111,3 +112,18 @@ export function extractInvoices(fragments) {
|
||||
return f;
|
||||
}).flat();
|
||||
}
|
||||
|
||||
export function extractHashtags(fragments) {
|
||||
return fragments.map(f => {
|
||||
if (typeof f === "string") {
|
||||
return f.split(HashtagRegex).map(i => {
|
||||
if (i.toLowerCase().startsWith("#")) {
|
||||
return <Hashtag>{i}</Hashtag>
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
});
|
||||
}
|
||||
return f;
|
||||
}).flat();
|
||||
}
|
||||
|
3
src/element/Hashtag.css
Normal file
3
src/element/Hashtag.css
Normal file
@ -0,0 +1,3 @@
|
||||
.hashtag {
|
||||
color: var(--highlight);
|
||||
}
|
11
src/element/Hashtag.js
Normal file
11
src/element/Hashtag.js
Normal file
@ -0,0 +1,11 @@
|
||||
import './Hashtag.css'
|
||||
|
||||
const Hashtag = ({ children }) => {
|
||||
return (
|
||||
<span className="hashtag">
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export default Hashtag
|
@ -5,7 +5,7 @@ import { useNavigate } from "react-router-dom";
|
||||
|
||||
import Event from "../nostr/Event";
|
||||
import ProfileImage from "./ProfileImage";
|
||||
import { extractLinks, extractMentions, extractInvoices } from "../Text";
|
||||
import { extractLinks, extractMentions, extractInvoices, extractHashtags } from "../Text";
|
||||
import { eventLink, hexToBech32 } from "../Util";
|
||||
import NoteFooter from "./NoteFooter";
|
||||
import NoteTime from "./NoteTime";
|
||||
@ -32,6 +32,7 @@ export default function Note(props) {
|
||||
let fragments = extractLinks([body]);
|
||||
fragments = extractMentions(fragments, ev.Tags, users);
|
||||
fragments = extractInvoices(fragments);
|
||||
fragments = extractHashtags(fragments);
|
||||
if (deletion?.length > 0) {
|
||||
return (
|
||||
<>
|
||||
|
@ -272,7 +272,7 @@ body.scroll-lock {
|
||||
}
|
||||
|
||||
.root-tabs {
|
||||
padding: 0 2px;
|
||||
padding: 0;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import useProfile from "../feed/ProfileFeed";
|
||||
import FollowButton from "../element/FollowButton";
|
||||
import { extractLnAddress, parseId } from "../Util";
|
||||
import Timeline from "../element/Timeline";
|
||||
import { extractLinks } from '../Text'
|
||||
import { extractLinks, extractHashtags } from '../Text'
|
||||
import LNURLTip from "../element/LNURLTip";
|
||||
import Nip05 from "../element/Nip05";
|
||||
import Copy from "../element/Copy";
|
||||
@ -36,6 +36,7 @@ export default function ProfilePage() {
|
||||
const isMe = loginPubKey === id;
|
||||
const [showLnQr, setShowLnQr] = useState(false);
|
||||
const [tab, setTab] = useState(ProfileTab.Notes);
|
||||
const about = extractHashtags(extractLinks([user?.about]))
|
||||
|
||||
useEffect(() => {
|
||||
setTab(ProfileTab.Notes);
|
||||
@ -60,7 +61,7 @@ export default function ProfilePage() {
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<p>{extractLinks([user?.about])}</p>
|
||||
<p>{about}</p>
|
||||
|
||||
{user?.website && (
|
||||
<div className="website f-ellipsis">
|
||||
|
Loading…
x
Reference in New Issue
Block a user