mirror of
https://github.com/irislib/iris-messenger.git
synced 2024-10-18 06:03:22 +00:00
wip separate files for different embed types
This commit is contained in:
parent
375066f7ee
commit
9bf0c04692
@ -306,7 +306,7 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
// Spotify album
|
||||
// SpotifyTrack album
|
||||
if (settings.enableSpotify !== false) {
|
||||
const spotifyRegex =
|
||||
/(?:https?:\/\/)?(?:www\.)?(?:open\.spotify\.com\/album\/)([\w-]+)(?:\S+)?/g;
|
||||
@ -327,7 +327,7 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
// Spotify playlist
|
||||
// SpotifyTrack playlist
|
||||
if (settings.enableSpotify !== false) {
|
||||
const spotifyPlaylistRegex =
|
||||
/(?:https?:\/\/)?(?:www\.)?(?:open\.spotify\.com\/playlist\/)([\w-]+)(?:\S+)?/g;
|
||||
|
32
src/js/components/HyperText.tsx
Normal file
32
src/js/components/HyperText.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { memo } from 'react';
|
||||
import reactStringReplace from 'react-string-replace';
|
||||
import { Event } from 'nostr-tools';
|
||||
|
||||
import { allEmbeds, textEmbeds } from './embed';
|
||||
|
||||
const HyperText = memo(
|
||||
({ children, event, textOnly }: { children: string; event?: Event; textOnly?: boolean }) => {
|
||||
let processedChildren = [children.trim()];
|
||||
|
||||
const embeds = textOnly ? textEmbeds : allEmbeds;
|
||||
|
||||
embeds.forEach((embed) => {
|
||||
processedChildren = reactStringReplace(processedChildren, embed.regex, (match, i) => {
|
||||
return embed.component({
|
||||
match,
|
||||
index: i,
|
||||
event,
|
||||
key: `${match}-${i}`,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
processedChildren = processedChildren.map((x) =>
|
||||
typeof x === 'string' ? x.replace(/^\n+|\n+$/g, '') : x,
|
||||
);
|
||||
|
||||
return <>{processedChildren}</>;
|
||||
},
|
||||
);
|
||||
|
||||
export default HyperText;
|
@ -10,6 +10,7 @@ import { DecryptedEvent } from '../views/chat/ChatMessages';
|
||||
|
||||
import Name from './user/Name';
|
||||
import Torrent from './Torrent';
|
||||
import HyperText from "./HyperText";
|
||||
|
||||
type Props = {
|
||||
event: DecryptedEvent;
|
||||
@ -81,7 +82,6 @@ const PrivateMessage = ({ event, selfAuthored, showName, torrentId }: Props) =>
|
||||
};
|
||||
|
||||
const emojiOnly = text && text.length === 2 && Helpers.isEmoji(text);
|
||||
const formattedText = Helpers.highlightEverything(text || '');
|
||||
// TODO opts.onImageClick show image in modal
|
||||
|
||||
const time =
|
||||
@ -108,7 +108,7 @@ const PrivateMessage = ({ event, selfAuthored, showName, torrentId }: Props) =>
|
||||
</div>
|
||||
{torrentId && <Torrent torrentId={torrentId} />}
|
||||
<div className={`preformatted-wrap text-base ${emojiOnly ? 'text-4xl' : ''}`}>
|
||||
{formattedText}
|
||||
<HyperText event={event}>{text}</HyperText>
|
||||
</div>
|
||||
<div className={`${selfAuthored ? 'text-right' : 'text-left'} text-xs text-white`}>
|
||||
{event.id ? Helpers.getRelativeTimeText(time) : Helpers.formatTime(time)}
|
||||
|
0
src/js/components/embed/AppleMusic.tsx
Normal file
0
src/js/components/embed/AppleMusic.tsx
Normal file
0
src/js/components/embed/ApplePodcast.tsx
Normal file
0
src/js/components/embed/ApplePodcast.tsx
Normal file
0
src/js/components/embed/Audio.tsx
Normal file
0
src/js/components/embed/Audio.tsx
Normal file
17
src/js/components/embed/Hashtag.tsx
Normal file
17
src/js/components/embed/Hashtag.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { Link } from 'preact-router';
|
||||
|
||||
import Embed from './index';
|
||||
|
||||
const Hashtag: Embed = {
|
||||
regex: /(?<=\s|^)(#\w+)/g,
|
||||
component: ({ match, key }) => {
|
||||
return (
|
||||
<Link key={key} href={`/search/${encodeURIComponent(match)}`} className="link">
|
||||
{' '}
|
||||
{match}{' '}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default Hashtag;
|
36
src/js/components/embed/Image.tsx
Normal file
36
src/js/components/embed/Image.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import Modal from '../modal/Modal';
|
||||
import SafeImg from '../SafeImg';
|
||||
|
||||
import Embed from './index';
|
||||
import Show from "../helpers/Show";
|
||||
|
||||
const Image: Embed = {
|
||||
regex: /(https?:\/\/.*\.(?:png|jpg|jpeg|gif|svg|webp)(?:\?\S*)?)/gi,
|
||||
component: ({ match, key }) => {
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const onClick = (e) => {
|
||||
e.stopPropagation();
|
||||
setShowModal(true);
|
||||
};
|
||||
return (
|
||||
<div key={key}>
|
||||
<div className="relative w-full overflow-hidden object-contain my-2">
|
||||
<SafeImg
|
||||
onClick={onClick}
|
||||
className="rounded max-h-[70vh] md:max-h-96 max-w-full cursor-pointer"
|
||||
src={match}
|
||||
/>
|
||||
</div>
|
||||
<Show when={showModal}>
|
||||
<Modal onClose={() => setShowModal(false)}>
|
||||
<SafeImg className="rounded max-h-[90vh] max-w-[90vw]" src={match} />
|
||||
</Modal>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default Image;
|
22
src/js/components/embed/Instagram.tsx
Normal file
22
src/js/components/embed/Instagram.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import Embed from './index';
|
||||
|
||||
const Instagram: Embed = {
|
||||
regex: /(?:https?:\/\/)?(?:www\.)?(?:instagram\.com\/)((?:p|reel)\/[\w-]{11})(?:\S+)?/g,
|
||||
component: ({ match, key }) => {
|
||||
return (
|
||||
<iframe
|
||||
className="instagram"
|
||||
key={key}
|
||||
width="650"
|
||||
height="400"
|
||||
style={{ maxWidth: '100%' }}
|
||||
src={`https://instagram.com/${match}/embed`}
|
||||
frameBorder="0"
|
||||
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default Instagram;
|
0
src/js/components/embed/LightningUri.tsx
Normal file
0
src/js/components/embed/LightningUri.tsx
Normal file
23
src/js/components/embed/SoundCloud.tsx
Normal file
23
src/js/components/embed/SoundCloud.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import Embed from './index';
|
||||
|
||||
const SoundCloud: Embed = {
|
||||
regex:
|
||||
/(?:https?:\/\/)?(?:www\.)?(soundcloud\.com\/(?!live)[a-zA-Z0-9-_]+\/[a-zA-Z0-9-_]+)(?:\?.*)?/g,
|
||||
component: ({ match, key }) => {
|
||||
return (
|
||||
<iframe
|
||||
key={key}
|
||||
className="audio"
|
||||
scrolling="no"
|
||||
width="650"
|
||||
height="380"
|
||||
style={{ maxWidth: '100%' }}
|
||||
src={`https://w.soundcloud.com/player/?url=${match}`}
|
||||
frameBorder="0"
|
||||
allow="encrypted-media"
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default SoundCloud;
|
0
src/js/components/embed/Tidal.tsx
Normal file
0
src/js/components/embed/Tidal.tsx
Normal file
0
src/js/components/embed/TikTok.tsx
Normal file
0
src/js/components/embed/TikTok.tsx
Normal file
0
src/js/components/embed/Torrent.tsx
Normal file
0
src/js/components/embed/Torrent.tsx
Normal file
0
src/js/components/embed/Twitch.tsx
Normal file
0
src/js/components/embed/Twitch.tsx
Normal file
0
src/js/components/embed/TwitchChannel.tsx
Normal file
0
src/js/components/embed/TwitchChannel.tsx
Normal file
24
src/js/components/embed/Twitter.tsx
Normal file
24
src/js/components/embed/Twitter.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import Embed from './index';
|
||||
|
||||
const Twitter: Embed = {
|
||||
regex: /(?:^|\s)(?:@)?(https?:\/\/twitter.com\/\w+\/status\/\d+\S*)(?![\w/])/g,
|
||||
component: ({ match, key }) => {
|
||||
return (
|
||||
<iframe
|
||||
style={{
|
||||
maxWidth: '350px',
|
||||
height: '450px',
|
||||
backgroundColor: 'white',
|
||||
display: 'block',
|
||||
}}
|
||||
key={key}
|
||||
scrolling="no"
|
||||
height={250}
|
||||
width={550}
|
||||
src={`https://twitframe.com/show?url=${encodeURIComponent(match)}`}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default Twitter;
|
17
src/js/components/embed/Url.tsx
Normal file
17
src/js/components/embed/Url.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { Link } from 'preact-router';
|
||||
|
||||
import Embed from './index';
|
||||
|
||||
const Url: Embed = {
|
||||
regex: /(https?:\/\/[^\s]+)/g,
|
||||
component: ({ match, key }) => {
|
||||
const url = match.replace(/^(https:\/\/)?iris.to/, '');
|
||||
return (
|
||||
<Link key={key} className="link" target="_blank" href={url}>
|
||||
{match.replace(/^https?:\/\//, '').replace(/\/$/, '')}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default Url;
|
20
src/js/components/embed/Video.tsx
Normal file
20
src/js/components/embed/Video.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import Embed from './index';
|
||||
|
||||
const Video: Embed = {
|
||||
regex: /(https?:\/\/.*\.(?:mp4|webm|ogg|mov)(?:\?\S*)?)/gi,
|
||||
component: ({ match, key }) => (
|
||||
<div key={key} className="relative w-full overflow-hidden object-contain my-2">
|
||||
<video
|
||||
className="rounded max-h-[70vh] md:max-h-96 max-w-full"
|
||||
src={match}
|
||||
controls
|
||||
muted
|
||||
autoPlay
|
||||
loop
|
||||
poster={`https://imgproxy.iris.to/thumbnail/638/${match}`}
|
||||
></video>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export default Video;
|
0
src/js/components/embed/WavLake.tsx
Normal file
0
src/js/components/embed/WavLake.tsx
Normal file
21
src/js/components/embed/YouTube.tsx
Normal file
21
src/js/components/embed/YouTube.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import Embed from './index';
|
||||
|
||||
const YouTube: Embed = {
|
||||
regex:
|
||||
/(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=|shorts\/|live\/))([\w-]{11})(?:\S+)?/g,
|
||||
component: ({ match, key }) => {
|
||||
return (
|
||||
<iframe
|
||||
key={key}
|
||||
width="650"
|
||||
height="400"
|
||||
src={`https://www.youtube.com/embed/${match}`}
|
||||
frameBorder="0"
|
||||
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default YouTube;
|
48
src/js/components/embed/index.ts
Normal file
48
src/js/components/embed/index.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { Event } from 'nostr-tools';
|
||||
import { JSX } from 'preact';
|
||||
|
||||
import InlineMention from './nostr/InlineMention';
|
||||
import Nip19 from './nostr/Nip19';
|
||||
import NostrEvent from './nostr/NostrNote';
|
||||
import NostrNpub from './nostr/NostrNpub';
|
||||
import SpotifyTrack from './spotify/SpotifyTrack';
|
||||
import Hashtag from './Hashtag';
|
||||
import Image from './Image';
|
||||
import Instagram from './Instagram';
|
||||
import SoundCloud from './SoundCloud';
|
||||
import Twitter from './Twitter';
|
||||
import Url from './Url';
|
||||
import Video from './Video';
|
||||
import Youtube from './YouTube';
|
||||
|
||||
export type EmbedProps = {
|
||||
match: string;
|
||||
index?: number;
|
||||
event?: Event;
|
||||
key: string;
|
||||
};
|
||||
|
||||
type Embed = {
|
||||
regex: RegExp;
|
||||
component: (props: EmbedProps) => JSX.Element;
|
||||
};
|
||||
|
||||
export const allEmbeds = [
|
||||
Image,
|
||||
Video,
|
||||
Youtube,
|
||||
Instagram,
|
||||
Twitter,
|
||||
SoundCloud,
|
||||
SpotifyTrack,
|
||||
NostrNpub,
|
||||
NostrEvent,
|
||||
Nip19,
|
||||
Hashtag,
|
||||
InlineMention,
|
||||
Url,
|
||||
];
|
||||
|
||||
export const textEmbeds = [NostrNpub, Url, Hashtag];
|
||||
|
||||
export default Embed;
|
41
src/js/components/embed/nostr/InlineMention.tsx
Normal file
41
src/js/components/embed/nostr/InlineMention.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
// mentions like #[3], can refer to event or user
|
||||
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { Link } from 'preact-router';
|
||||
|
||||
import EventComponent from '../../events/EventComponent';
|
||||
import Name from '../../user/Name';
|
||||
|
||||
import Embed from '../index';
|
||||
|
||||
const fail = (s: string) => `#[${s}]`;
|
||||
|
||||
const InlineMention: Embed = {
|
||||
regex: /#\[([0-9]+)]/g,
|
||||
component: ({ match, index, event, key }) => {
|
||||
if (!event?.tags) {
|
||||
console.log('no tags', event);
|
||||
return <>{fail(match)}</>;
|
||||
}
|
||||
const tag = event.tags[parseInt(match)];
|
||||
if (!tag) {
|
||||
console.log('no matching tag', index, event);
|
||||
return <>{fail(match)}</>;
|
||||
}
|
||||
const [type, id] = tag;
|
||||
if (type === 'p') {
|
||||
return (
|
||||
<Link key={key} href={`/${nip19.npubEncode(id)}`} className="link">
|
||||
<Name pub={id} hideBadge={true} />
|
||||
</Link>
|
||||
);
|
||||
} else if (type === 'e') {
|
||||
return <EventComponent id={id} key={id} asInlineQuote={true} />;
|
||||
} else {
|
||||
console.log('unknown tag type', type, index, event);
|
||||
return <>{fail(match)}</>;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default InlineMention;
|
40
src/js/components/embed/nostr/Nip19.tsx
Normal file
40
src/js/components/embed/nostr/Nip19.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { Link } from 'preact-router';
|
||||
|
||||
import EventComponent from '../../events/EventComponent';
|
||||
import Name from '../../user/Name';
|
||||
|
||||
import Embed from '../index';
|
||||
|
||||
const nip19Regex = /\bnostr:(n(?:event|profile)1\w+)\b/g;
|
||||
|
||||
const NostrUser: Embed = {
|
||||
regex: nip19Regex,
|
||||
component: ({ match, key }) => {
|
||||
try {
|
||||
const { type, data } = nip19.decode(match);
|
||||
if (type === 'nprofile') {
|
||||
return (
|
||||
<>
|
||||
{' '}
|
||||
<Link key={key} className="text-iris-blue hover:underline" href={`/${data.pubkey}`}>
|
||||
<Name pub={data.pubkey} />
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
} else if (type === 'nevent') {
|
||||
// same as note
|
||||
return (
|
||||
<div key={key} className="rounded-lg border border-gray-500 my-2">
|
||||
<EventComponent id={data.id} asInlineQuote={true} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
return <span key={key}>{match}</span>;
|
||||
},
|
||||
};
|
||||
|
||||
export default NostrUser;
|
17
src/js/components/embed/nostr/NostrNote.tsx
Normal file
17
src/js/components/embed/nostr/NostrNote.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import Key from '../../../nostr/Key';
|
||||
import EventComponent from '../../events/EventComponent';
|
||||
|
||||
import Embed from '../index';
|
||||
|
||||
const eventRegex =
|
||||
/(?:^|\s|nostr:|(?:https?:\/\/[\w./]+)|iris\.to\/|snort\.social\/e\/|damus\.io\/)+((?:@)?note[a-zA-Z0-9]{59,60})(?![\w/])/gi;
|
||||
|
||||
const NostrUser: Embed = {
|
||||
regex: eventRegex,
|
||||
component: ({ match, key }) => {
|
||||
const hex = Key.toNostrHexAddress(match.replace('@', ''))!;
|
||||
return <EventComponent key={key} id={hex} asInlineQuote={true} />;
|
||||
},
|
||||
};
|
||||
|
||||
export default NostrUser;
|
22
src/js/components/embed/nostr/NostrNpub.tsx
Normal file
22
src/js/components/embed/nostr/NostrNpub.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { Link } from 'preact-router';
|
||||
|
||||
import Name from '../../user/Name';
|
||||
|
||||
import Embed from '../index';
|
||||
|
||||
const pubKeyRegex =
|
||||
/(?:^|\s|nostr:|(?:https?:\/\/[\w./]+)|iris\.to\/|snort\.social\/p\/|damus\.io\/)+((?:@)?npub[a-zA-Z0-9]{59,60})(?![\w/])/gi;
|
||||
|
||||
const NostrNpub: Embed = {
|
||||
regex: pubKeyRegex,
|
||||
component: ({ match, key }) => {
|
||||
const pub = match.replace('@', '');
|
||||
return (
|
||||
<Link key={key} href={`/${pub}`} className="link mr-1">
|
||||
<Name pub={pub} hideBadge={true} />
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default NostrNpub;
|
0
src/js/components/embed/spotify/SpotifyAlbum.tsx
Normal file
0
src/js/components/embed/spotify/SpotifyAlbum.tsx
Normal file
0
src/js/components/embed/spotify/SpotifyPlaylist.tsx
Normal file
0
src/js/components/embed/spotify/SpotifyPlaylist.tsx
Normal file
0
src/js/components/embed/spotify/SpotifyPodcast.tsx
Normal file
0
src/js/components/embed/spotify/SpotifyPodcast.tsx
Normal file
23
src/js/components/embed/spotify/SpotifyTrack.tsx
Normal file
23
src/js/components/embed/spotify/SpotifyTrack.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import Embed from '../index';
|
||||
|
||||
const SpotifyTrack: Embed = {
|
||||
regex: /(?:https?:\/\/)?(?:www\.)?(?:open\.spotify\.com\/track\/)([\w-]+)(?:\S+)?/g,
|
||||
component: ({ match, key }) => {
|
||||
return (
|
||||
<iframe
|
||||
className="audio"
|
||||
scrolling="no"
|
||||
key={key}
|
||||
width="650"
|
||||
height="200"
|
||||
style={{ maxWidth: '100%' }}
|
||||
src={`https://open.spotify.com/embed/track/${match}?utm_source=oembed`}
|
||||
frameBorder="0"
|
||||
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default SpotifyTrack;
|
@ -6,7 +6,7 @@ import localState from '../../../LocalState';
|
||||
import SocialNetwork from '../../../nostr/SocialNetwork';
|
||||
import { translate as t } from '../../../translations/Translation.mjs';
|
||||
import Show from '../../helpers/Show';
|
||||
import ImageModal from '../../modal/Image';
|
||||
import HyperText from '../../HyperText';
|
||||
import PublicMessageForm from '../../PublicMessageForm';
|
||||
import Torrent from '../../Torrent';
|
||||
import Reactions from '../buttons/ReactionButtons';
|
||||
@ -32,7 +32,6 @@ const Content = ({ standalone, isQuote, fullWidth, asInlineQuote, event, meta })
|
||||
const [translatedText, setTranslatedText] = useState('');
|
||||
const [showMore, setShowMore] = useState(false);
|
||||
const [name, setName] = useState('');
|
||||
const [showImageModal, setShowImageModal] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (standalone) {
|
||||
@ -74,16 +73,6 @@ const Content = ({ standalone, isQuote, fullWidth, asInlineQuote, event, meta })
|
||||
? `${lines.slice(0, MSG_TRUNCATE_LINES).join('\n')}...`
|
||||
: text;
|
||||
|
||||
text = Helpers.highlightEverything(text.trim(), event, {
|
||||
showMentionedMessages: !asInlineQuote,
|
||||
onImageClick: (e) => imageClicked(e),
|
||||
});
|
||||
|
||||
function imageClicked(e) {
|
||||
e.preventDefault();
|
||||
setShowImageModal(true);
|
||||
}
|
||||
|
||||
function isTooLong() {
|
||||
return (
|
||||
attachments?.length > 1 ||
|
||||
@ -109,7 +98,7 @@ const Content = ({ standalone, isQuote, fullWidth, asInlineQuote, event, meta })
|
||||
</Show>
|
||||
<Show when={text?.length > 0}>
|
||||
<div className={`preformatted-wrap pb-1 ${emojiOnly && 'text-2xl'}`}>
|
||||
{text}
|
||||
<HyperText event={event}>{text}</HyperText>
|
||||
<Show when={translatedText}>
|
||||
<p>
|
||||
<i>{translatedText}</i>
|
||||
@ -148,12 +137,6 @@ const Content = ({ standalone, isQuote, fullWidth, asInlineQuote, event, meta })
|
||||
placeholder={t('write_your_reply')}
|
||||
/>
|
||||
</Show>
|
||||
<Show when={showImageModal}>
|
||||
<ImageModal
|
||||
images={attachments?.map((a) => a.data)}
|
||||
onClose={() => setShowImageModal(false)}
|
||||
/>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -30,7 +30,6 @@ const Overlay = styled.div<Props>`
|
||||
const ModalContentContainer = styled.div<{ width?: string; height?: string }>`
|
||||
width: ${(props) => props.width || 'auto'};
|
||||
height: ${(props) => props.height || 'auto'};
|
||||
max-height: calc(100% - 40px);
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -17,6 +17,7 @@ import ProfileDropdown from './Dropdown';
|
||||
import Name from './Name';
|
||||
import ProfilePicture from './ProfilePicture';
|
||||
import Stats from './Stats';
|
||||
import HyperText from "../HyperText";
|
||||
|
||||
const ProfileCard = (props: { hexPub: string; npub: string }) => {
|
||||
const { hexPub, npub } = props;
|
||||
@ -197,7 +198,9 @@ const ProfileCard = (props: { hexPub: string; npub: string }) => {
|
||||
</div>
|
||||
<Stats address={hexPub} />
|
||||
<div className="py-2">
|
||||
<p className="text-sm">{profile.about}</p>
|
||||
<p className="text-sm">
|
||||
<HyperText textOnly={true}>{profile.about.slice(0, 500)}</HyperText>
|
||||
</p>
|
||||
<div className="flex flex-1 flex-row align-center justify-center mt-4">
|
||||
<Show when={lightning}>
|
||||
<div className="flex-1">
|
||||
|
@ -171,7 +171,9 @@ function ChatMessages({ id }) {
|
||||
/>
|
||||
</div>
|
||||
<Show when={showQr}>
|
||||
<QrCode data={'nostr:' + formatPrivateKey()} />
|
||||
<div className="mt-4">
|
||||
<QrCode data={'nostr:' + formatPrivateKey()} />
|
||||
</div>
|
||||
</Show>
|
||||
</Show>
|
||||
<Show when={!isGroup && Key.toNostrHexAddress(id) !== myPub}>
|
||||
|
Loading…
Reference in New Issue
Block a user