feat: a link profile image
This commit is contained in:
parent
2ed38d1b97
commit
ec4e6498d3
@ -19,4 +19,5 @@
|
||||
border: 1px solid var(--font-tertiary-color);
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -327,10 +327,9 @@ export default function Note(props: NoteProps) {
|
||||
{options.showHeader && (
|
||||
<div className="header flex">
|
||||
<ProfileImage
|
||||
autoWidth={false}
|
||||
pubkey={ev.pubkey}
|
||||
subHeader={replyTag() ?? undefined}
|
||||
linkToProfile={opt?.canClick === undefined}
|
||||
link={opt?.canClick === undefined ? undefined : ""}
|
||||
/>
|
||||
{(options.showTime || options.showBookmarked) && (
|
||||
<div className="info">
|
||||
|
@ -293,7 +293,7 @@ export function NoteCreator() {
|
||||
ev.stopPropagation = true;
|
||||
LoginStore.switchAccount(a);
|
||||
}}>
|
||||
<ProfileImage pubkey={a} linkToProfile={false} />
|
||||
<ProfileImage pubkey={a} link={""} />
|
||||
</MenuItem>
|
||||
));
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
.pfp {
|
||||
display: flex;
|
||||
display: grid;
|
||||
grid-template-columns: min-content auto;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.pfp .avatar-wrapper {
|
||||
@ -14,7 +18,7 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pfp a {
|
||||
a.pfp {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@ -25,6 +29,10 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.pfp .subheader .about {
|
||||
max-width: calc(100vw - 140px);
|
||||
.pfp .profile-name {
|
||||
max-width: stretch;
|
||||
}
|
||||
|
||||
.pfp a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import "./ProfileImage.css";
|
||||
|
||||
import { useMemo } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { HexKey, NostrPrefix } from "@snort/nostr";
|
||||
|
||||
import { useUserProfile } from "Hooks/useUserProfile";
|
||||
@ -9,7 +8,7 @@ import { hexToBech32, profileLink } from "Util";
|
||||
import Avatar from "Element/Avatar";
|
||||
import Nip05 from "Element/Nip05";
|
||||
import { MetadataCache } from "Cache";
|
||||
import usePageWidth from "Hooks/usePageWidth";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export interface ProfileImageProps {
|
||||
pubkey: HexKey;
|
||||
@ -17,10 +16,8 @@ export interface ProfileImageProps {
|
||||
showUsername?: boolean;
|
||||
className?: string;
|
||||
link?: string;
|
||||
autoWidth?: boolean;
|
||||
defaultNip?: string;
|
||||
verifyNip?: boolean;
|
||||
linkToProfile?: boolean;
|
||||
overrideUsername?: string;
|
||||
}
|
||||
|
||||
@ -30,50 +27,32 @@ export default function ProfileImage({
|
||||
showUsername = true,
|
||||
className,
|
||||
link,
|
||||
autoWidth = true,
|
||||
defaultNip,
|
||||
verifyNip,
|
||||
linkToProfile = true,
|
||||
overrideUsername,
|
||||
}: ProfileImageProps) {
|
||||
const navigate = useNavigate();
|
||||
const user = useUserProfile(pubkey);
|
||||
const nip05 = defaultNip ? defaultNip : user?.nip05;
|
||||
const width = usePageWidth();
|
||||
|
||||
const name = useMemo(() => {
|
||||
return overrideUsername ?? getDisplayName(user, pubkey);
|
||||
}, [user, pubkey, overrideUsername]);
|
||||
|
||||
if (!pubkey && !link) {
|
||||
link = "#";
|
||||
}
|
||||
|
||||
const onAvatarClick = () => {
|
||||
if (linkToProfile) {
|
||||
navigate(link ?? profileLink(pubkey));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`pfp f-ellipsis${className ? ` ${className}` : ""}`} onClick={onAvatarClick}>
|
||||
<Link className={`pfp${className ? ` ${className}` : ""}`} to={link === undefined ? profileLink(pubkey) : ""}>
|
||||
<div className="avatar-wrapper">
|
||||
<Avatar user={user} />
|
||||
</div>
|
||||
{showUsername && (
|
||||
<div className="profile-name">
|
||||
<div className="f-ellipsis">
|
||||
<div className="username">
|
||||
<div className="display-name">
|
||||
<div>{name.trim()}</div>
|
||||
{nip05 && <Nip05 nip05={nip05} pubkey={pubkey} verifyNip={verifyNip} />}
|
||||
</div>
|
||||
</div>
|
||||
<div className="subheader" style={{ width: autoWidth ? width - 190 : "" }}>
|
||||
{subHeader}
|
||||
</div>
|
||||
<div className="subheader">{subHeader}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,28 +1,23 @@
|
||||
.reactions-modal .modal-body {
|
||||
padding: 0;
|
||||
max-width: 586px;
|
||||
}
|
||||
|
||||
.reactions-view {
|
||||
padding: 24px 32px;
|
||||
background-color: #1b1b1b;
|
||||
border-radius: 16px;
|
||||
position: relative;
|
||||
min-height: 33vh;
|
||||
}
|
||||
|
||||
.light .reactions-view {
|
||||
.light .reactions-modal .modal-body {
|
||||
background-color: var(--note-bg);
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.reactions-view {
|
||||
.reactions-modal .modal-body {
|
||||
padding: 12px 16px;
|
||||
margin-top: -160px;
|
||||
max-width: calc(100vw - 32px);
|
||||
}
|
||||
}
|
||||
|
||||
.reactions-view .close {
|
||||
.reactions-modal .modal-body .close {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 16px;
|
||||
@ -30,18 +25,18 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.reactions-view .close:hover {
|
||||
.reactions-modal .modal-body .close:hover {
|
||||
color: var(--font-tertiary-color);
|
||||
}
|
||||
|
||||
.reactions-view .reactions-header {
|
||||
.reactions-modal .modal-body .reactions-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.reactions-view .reactions-header h2 {
|
||||
.reactions-modal .modal-body .reactions-header h2 {
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
font-weight: 600;
|
||||
@ -49,26 +44,25 @@
|
||||
line-height: 19px;
|
||||
}
|
||||
|
||||
.reactions-view .body {
|
||||
.reactions-modal .modal-body .body {
|
||||
overflow: scroll;
|
||||
height: 320px;
|
||||
height: 40vh;
|
||||
-ms-overflow-style: none; /* for Internet Explorer, Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
|
||||
.reactions-view .body::-webkit-scrollbar {
|
||||
.reactions-modal .modal-body .body::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.reactions-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
display: grid;
|
||||
grid-template-columns: 52px auto;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.reactions-item .reaction-icon {
|
||||
width: 52px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@ -93,12 +87,8 @@
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
.reactions-item .zap-comment {
|
||||
width: 332px;
|
||||
}
|
||||
|
||||
@media (max-width: 520px) {
|
||||
.reactions-view .tab.disabled {
|
||||
.reactions-modal .modal-body .tab.disabled {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import "./Reactions.css";
|
||||
|
||||
import { useState, useMemo, useEffect } from "react";
|
||||
import { useIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import { TaggedRawEvent } from "@snort/nostr";
|
||||
|
||||
import { formatShort } from "Number";
|
||||
@ -75,7 +74,6 @@ const Reactions = ({ show, setShow, positive, negative, reposts, zaps }: Reactio
|
||||
|
||||
return show ? (
|
||||
<Modal className="reactions-modal" onClose={onClose}>
|
||||
<div className="reactions-view">
|
||||
<div className="close" onClick={onClose}>
|
||||
<Icon name="close" />
|
||||
</div>
|
||||
@ -91,7 +89,7 @@ const Reactions = ({ show, setShow, positive, negative, reposts, zaps }: Reactio
|
||||
return (
|
||||
<div key={ev.id} className="reactions-item">
|
||||
<div className="reaction-icon">{ev.content === "+" ? <Icon name="heart" /> : ev.content}</div>
|
||||
<ProfileImage autoWidth={false} pubkey={ev.pubkey} />
|
||||
<ProfileImage pubkey={ev.pubkey} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@ -105,13 +103,9 @@ const Reactions = ({ show, setShow, positive, negative, reposts, zaps }: Reactio
|
||||
<span className="zap-amount">{formatShort(z.amount)}</span>
|
||||
</div>
|
||||
<ProfileImage
|
||||
autoWidth={false}
|
||||
pubkey={z.anonZap ? "" : z.sender}
|
||||
subHeader={
|
||||
<div className="f-ellipsis zap-comment" title={z.content}>
|
||||
{z.content}
|
||||
</div>
|
||||
}
|
||||
subHeader={<div title={z.content}>{z.content}</div>}
|
||||
link={z.anonZap ? "" : undefined}
|
||||
overrideUsername={z.anonZap ? formatMessage({ defaultMessage: "Anonymous" }) : undefined}
|
||||
/>
|
||||
</div>
|
||||
@ -125,23 +119,22 @@ const Reactions = ({ show, setShow, positive, negative, reposts, zaps }: Reactio
|
||||
<div className="reaction-icon">
|
||||
<Icon name="repost" size={16} />
|
||||
</div>
|
||||
<ProfileImage autoWidth={false} pubkey={ev.pubkey} />
|
||||
<ProfileImage pubkey={ev.pubkey} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{tab.value === 3 &&
|
||||
dislikes.map(ev => {
|
||||
return (
|
||||
<div key={ev.id} className="reactions-item">
|
||||
<div key={ev.id} className="reactions-item f-ellipsis">
|
||||
<div className="reaction-icon">
|
||||
<Icon name="dislike" />
|
||||
</div>
|
||||
<ProfileImage autoWidth={false} pubkey={ev.pubkey} />
|
||||
<ProfileImage pubkey={ev.pubkey} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
) : null;
|
||||
};
|
||||
|
@ -119,7 +119,7 @@ const Timeline = (props: TimelineProps) => {
|
||||
<>
|
||||
<div className="card latest-notes pointer" onClick={() => onShowLatest()} ref={ref}>
|
||||
{latestAuthors.slice(0, 3).map(p => {
|
||||
return <ProfileImage pubkey={p} showUsername={false} linkToProfile={false} />;
|
||||
return <ProfileImage pubkey={p} showUsername={false} link={""} />;
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="{n} new {n, plural, =1 {note} other {notes}}"
|
||||
@ -130,7 +130,7 @@ const Timeline = (props: TimelineProps) => {
|
||||
{!inView && (
|
||||
<div className="card latest-notes latest-notes-fixed pointer fade-in" onClick={() => onShowLatest(true)}>
|
||||
{latestAuthors.slice(0, 3).map(p => {
|
||||
return <ProfileImage pubkey={p} showUsername={false} linkToProfile={false} />;
|
||||
return <ProfileImage pubkey={p} showUsername={false} link={""} />;
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="{n} new {n, plural, =1 {note} other {notes}}"
|
||||
|
@ -107,8 +107,8 @@ const Zap = ({ zap, showZapped = true }: { zap: ParsedZap; showZapped?: boolean
|
||||
return valid && sender ? (
|
||||
<div className="zap note card">
|
||||
<div className="header">
|
||||
<ProfileImage autoWidth={false} pubkey={sender} />
|
||||
{receiver !== pubKey && showZapped && <ProfileImage autoWidth={false} pubkey={unwrap(receiver)} />}
|
||||
<ProfileImage pubkey={sender} />
|
||||
{receiver !== pubKey && showZapped && <ProfileImage pubkey={unwrap(receiver)} />}
|
||||
<div className="amount">
|
||||
<span className="amount-number">
|
||||
<FormattedMessage {...messages.Sats} values={{ n: formatShort(amount ?? 0) }} />
|
||||
@ -151,7 +151,6 @@ export const ZapsSummary = ({ zaps }: ZapsSummaryProps) => {
|
||||
<div className="summary">
|
||||
{sender && (
|
||||
<ProfileImage
|
||||
autoWidth={false}
|
||||
pubkey={anonZap ? "" : sender}
|
||||
overrideUsername={anonZap ? formatMessage({ defaultMessage: "Anonymous" }) : undefined}
|
||||
/>
|
||||
|
@ -42,6 +42,7 @@
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
html.light {
|
||||
|
Loading…
x
Reference in New Issue
Block a user