show zapper avatars on the same notefooter row

This commit is contained in:
Martti Malmi 2024-01-11 12:00:53 +02:00
parent 536f8ddc5b
commit de6685ade3
10 changed files with 47 additions and 117 deletions

View File

@ -57,21 +57,6 @@
margin-top: 16px;
}
.note .footer .footer-reactions {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-left: auto;
gap: 48px;
}
@media (min-width: 720px) {
.note .footer .footer-reactions {
margin-left: 0;
}
}
.note > .header img:hover,
.note > .header .name > .reply:hover {
cursor: pointer;

View File

@ -46,22 +46,3 @@
width: -webkit-fill-available;
aspect-ratio: 16 / 9;
}
.long-form-note .footer {
display: flex;
}
.long-form-note .footer .footer-reactions {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-left: auto;
gap: 48px;
}
@media (min-width: 720px) {
.long-form-note .footer .footer-reactions {
margin-left: 0;
}
}

View File

@ -55,8 +55,12 @@ export function Note(props: NoteProps) {
<NoteText {...props} translated={translated} showTranslation={showTranslation} />
{translated && <TranslationInfo translated={translated} setShowTranslation={setShowTranslation} />}
{ev.kind === EventKind.Polls && <Poll ev={ev} />}
{optionsMerged.showFooter && (
<div className="mt-4">
<NoteFooter ev={ev} replies={props.threadChains?.get(chainKey(ev))?.length} />
</div>
)}
</div>
{optionsMerged.showFooter && <NoteFooter ev={ev} replies={props.threadChains?.get(chainKey(ev))?.length} />}
</>
);
}

View File

@ -193,17 +193,20 @@ export default function NoteFooter(props: NoteFooterProps) {
const targets = getZapTarget();
if (targets) {
return (
<AsyncFooterIcon
className={didZap ? "reacted text-nostr-orange" : "hover:text-nostr-orange"}
{...longPress()}
title={formatMessage({ defaultMessage: "Zap", id: "fBI91o" })}
iconName={canFastZap ? "zapFast" : "zap"}
value={zapTotal}
onClick={e => fastZap(e)}
/>
<div className="flex flex-row gap-4 items-center">
<AsyncFooterIcon
className={didZap ? "reacted text-nostr-orange" : "hover:text-nostr-orange"}
{...longPress()}
title={formatMessage({ defaultMessage: "Zap", id: "fBI91o" })}
iconName={canFastZap ? "zapFast" : "zap"}
value={zapTotal}
onClick={e => fastZap(e)}
/>
<ZapsSummary zaps={zaps} />
</div>
);
}
return null;
return <div className="w-[18px]"></div>;
}
function repostIcon() {
@ -289,19 +292,14 @@ export default function NoteFooter(props: NoteFooterProps) {
};
return (
<>
<div className="footer">
<div className="footer-reactions">
{replyIcon()}
{repostIcon()}
{reactionIcon()}
{tipButton()}
{powIcon()}
</div>
<SendSats targets={getZapTarget()} onClose={() => setTip(false)} show={tip} note={ev.id} allocatePool={true} />
</div>
<ZapsSummary zaps={zaps} />
</>
<div className="flex flex-row justify-between gap-2 overflow-hidden w-[360px] flex-grow max-w-full h-6">
{replyIcon()}
{repostIcon()}
{reactionIcon()}
{powIcon()}
{tipButton()}
<SendSats targets={getZapTarget()} onClose={() => setTip(false)} show={tip} note={ev.id} allocatePool={true} />
</div>
);
}

View File

@ -12,10 +12,6 @@
line-height: 27px;
}
.thread-root.note > .footer {
padding-left: 0;
}
.thread-root.note {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
@ -26,8 +22,6 @@
border: 0;
}
.thread-note.note .zaps-summary,
.thread-note.note .footer,
.thread-note.note .body {
margin-left: 61px;
}

View File

@ -44,15 +44,6 @@
color: var(--font-secondary-color);
}
.zaps-summary {
display: flex;
flex-direction: row;
}
.note.thread-root .zaps-summary {
margin-left: 14px;
}
.top-zap {
font-size: 14px;
border: none;

View File

@ -1,50 +1,31 @@
import { ParsedZap } from "@snort/system";
import { useMemo } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import messages from "@/Components/messages";
import ProfileImage from "@/Components/User/ProfileImage";
import { AvatarGroup } from "@/Components/User/AvatarGroup";
import { dedupe } from "@/Utils";
interface ZapsSummaryProps {
zaps: ParsedZap[];
}
export const ZapsSummary = ({ zaps }: ZapsSummaryProps) => {
const { formatMessage } = useIntl();
const sortedZaps = useMemo(() => {
const sortedZappers = useMemo(() => {
const pub = [...zaps.filter(z => z.sender && z.valid)];
const priv = [...zaps.filter(z => !z.sender && z.valid)];
pub.sort((a, b) => b.amount - a.amount);
return pub.concat(priv);
return dedupe(pub.concat(priv).map(z => z.sender)).slice(0, 3);
}, [zaps]);
if (zaps.length === 0) {
return null;
}
const [topZap, ...restZaps] = sortedZaps;
const { sender, amount, anonZap } = topZap;
return (
<div className="zaps-summary">
{amount && (
<div className={`top-zap`}>
<div className="summary">
{sender && (
<ProfileImage
pubkey={anonZap ? "" : sender}
showFollowDistance={false}
overrideUsername={anonZap ? formatMessage({ defaultMessage: "Anonymous", id: "LXxsbk" }) : undefined}
/>
)}
{restZaps.length > 0 ? (
<FormattedMessage {...messages.Others} values={{ n: restZaps.length }} />
) : (
<FormattedMessage {...messages.Zapped} />
)}{" "}
<FormattedMessage {...messages.OthersZapped} values={{ n: restZaps.length }} />
</div>
<div className={`top-zap`}>
<div className="summary">
<AvatarGroup ids={sortedZappers} />
</div>
)}
</div>
</div>
);
};

View File

@ -0,0 +1,12 @@
import { HexKey } from "@snort/system";
import React from "react";
import ProfileImage from "@/Components/User/ProfileImage";
export function AvatarGroup({ ids }: { ids: HexKey[] }) {
return ids.map((a, index) => (
<div className={`inline-block ${index > 0 ? "-ml-5" : ""}`} key={a} style={{ zIndex: ids.length - index }}>
<ProfileImage showFollowDistance={false} pubkey={a} size={24} showUsername={false} />
</div>
));
}

View File

@ -2,9 +2,9 @@ import { HexKey, socialGraphInstance } from "@snort/system";
import React, { Fragment, useMemo } from "react";
import { FormattedMessage } from "react-intl";
import { AvatarGroup } from "@/Components/User/AvatarGroup";
import DisplayName from "@/Components/User/DisplayName";
import FollowDistanceIndicator from "@/Components/User/FollowDistanceIndicator";
import ProfileImage from "@/Components/User/ProfileImage";
import { ProfileLink } from "@/Components/User/ProfileLink";
const MAX_FOLLOWED_BY_FRIENDS = 3;
@ -19,17 +19,6 @@ export default function FollowedBy({ pubkey }: { pubkey: HexKey }) {
};
}, [pubkey, followDistance]);
const renderFollowedByFriends = () => {
return followedByFriendsArray.map((a, index) => (
<div
className={`inline-block ${index > 0 ? "-ml-5" : ""}`}
key={a}
style={{ zIndex: followedByFriendsArray.length - index }}>
<ProfileImage showFollowDistance={false} pubkey={a} size={24} showUsername={false} />
</div>
));
};
const renderFollowedByFriendsLinks = () => {
return followedByFriendsArray.map((a, index) => (
<Fragment key={a}>
@ -45,7 +34,7 @@ export default function FollowedBy({ pubkey }: { pubkey: HexKey }) {
<div className="flex flex-row items-center">
<div className="flex flex-row items-center">
<FollowDistanceIndicator className="p-2" pubkey={pubkey} />
{renderFollowedByFriends()}
<AvatarGroup ids={followedByFriendsArray} />
</div>
{totalFollowedByFriends > 0 && (
<div className="text-gray-light">

View File

@ -218,11 +218,6 @@ a.ext {
margin-bottom: -8px;
}
.card > .footer {
display: flex;
flex-direction: row;
}
.card .card-title {
font-size: x-large;
font-weight: bold;