forked from Kieran/snort
show zapper avatars on the same notefooter row
This commit is contained in:
parent
ee01623bf1
commit
3a73d53b5c
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
12
packages/app/src/Components/User/AvatarGroup.tsx
Normal file
12
packages/app/src/Components/User/AvatarGroup.tsx
Normal 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>
|
||||
));
|
||||
}
|
@ -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">
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user