Merge remote-tracking branch 'mmalmi/main'
This commit is contained in:
@ -448,7 +448,7 @@ export function NoteCreator() {
|
||||
className="note-creator-icon"
|
||||
link=""
|
||||
showUsername={false}
|
||||
showFollowingMark={false}
|
||||
showFollowDistance={false}
|
||||
/>
|
||||
{note.pollOptions === undefined && !note.replyTo && (
|
||||
<AsyncIcon
|
||||
|
@ -59,7 +59,7 @@ export const ZapsSummary = ({ zaps }: ZapsSummaryProps) => {
|
||||
{sender && (
|
||||
<ProfileImage
|
||||
pubkey={anonZap ? "" : sender}
|
||||
showFollowingMark={false}
|
||||
showFollowDistance={false}
|
||||
overrideUsername={anonZap ? formatMessage({ defaultMessage: "Anonymous" }) : undefined}
|
||||
/>
|
||||
)}
|
||||
|
@ -36,7 +36,7 @@ export function TimelineRenderer(props: TimelineRendererProps) {
|
||||
<>
|
||||
<div className="card latest-notes" onClick={() => props.showLatest(false)} ref={ref}>
|
||||
{props.latest.slice(0, 3).map(p => {
|
||||
return <ProfileImage pubkey={p} showUsername={false} link={""} showFollowingMark={false} />;
|
||||
return <ProfileImage pubkey={p} showUsername={false} link={""} showFollowDistance={false} />;
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="{n} new {n, plural, =1 {note} other {notes}}"
|
||||
@ -49,7 +49,7 @@ export function TimelineRenderer(props: TimelineRendererProps) {
|
||||
className="card latest-notes latest-notes-fixed pointer fade-in"
|
||||
onClick={() => props.showLatest(true)}>
|
||||
{props.latest.slice(0, 3).map(p => {
|
||||
return <ProfileImage pubkey={p} showUsername={false} link={""} showFollowingMark={false} />;
|
||||
return <ProfileImage pubkey={p} showUsername={false} link={""} showFollowDistance={false} />;
|
||||
})}
|
||||
<FormattedMessage
|
||||
defaultMessage="{n} new {n, plural, =1 {note} other {notes}}"
|
||||
|
@ -10,6 +10,34 @@ export interface ModalProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
let scrollbarWidth: number | null = null;
|
||||
|
||||
const getScrollbarWidth = () => {
|
||||
if (scrollbarWidth !== null) {
|
||||
return scrollbarWidth;
|
||||
}
|
||||
|
||||
const outer = document.createElement("div");
|
||||
outer.style.visibility = "hidden";
|
||||
outer.style.width = "100px";
|
||||
|
||||
document.body.appendChild(outer);
|
||||
|
||||
const widthNoScroll = outer.offsetWidth;
|
||||
outer.style.overflow = "scroll";
|
||||
|
||||
const inner = document.createElement("div");
|
||||
inner.style.width = "100%";
|
||||
outer.appendChild(inner);
|
||||
|
||||
const widthWithScroll = inner.offsetWidth;
|
||||
|
||||
outer.parentNode?.removeChild(outer);
|
||||
|
||||
scrollbarWidth = widthNoScroll - widthWithScroll;
|
||||
return scrollbarWidth;
|
||||
};
|
||||
|
||||
export default function Modal(props: ModalProps) {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape" && props.onClose) {
|
||||
@ -19,10 +47,13 @@ export default function Modal(props: ModalProps) {
|
||||
|
||||
useEffect(() => {
|
||||
document.body.classList.add("scroll-lock");
|
||||
document.body.style.paddingRight = `${getScrollbarWidth()}px`;
|
||||
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
|
||||
return () => {
|
||||
document.body.classList.remove("scroll-lock");
|
||||
document.body.style.paddingRight = "";
|
||||
document.removeEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
}, []);
|
||||
|
@ -16,6 +16,7 @@ export default function SearchBox() {
|
||||
const { formatMessage } = useIntl();
|
||||
const [search, setSearch] = useState("");
|
||||
const [searching, setSearching] = useState(false);
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
@ -120,13 +121,15 @@ export default function SearchBox() {
|
||||
value={search}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onBlur={() => setTimeout(() => setIsFocused(false), 150)}
|
||||
/>
|
||||
{searching ? (
|
||||
<Spinner width={24} height={24} />
|
||||
) : (
|
||||
<Icon name="search" size={24} onClick={() => navigate("/search")} />
|
||||
)}
|
||||
{search && !searching && (
|
||||
{search && !searching && isFocused && (
|
||||
<div
|
||||
className="absolute top-full mt-2 w-full border border-neutral-200 dark:border-neutral-700 bg-white dark:bg-black shadow-lg rounded-lg z-10 overflow-hidden"
|
||||
ref={resultListRef}>
|
||||
|
@ -166,7 +166,7 @@ export default function SendSats(props: SendSatsProps) {
|
||||
<ProfileImage
|
||||
pubkey={v.value}
|
||||
showUsername={false}
|
||||
showFollowingMark={false}
|
||||
showFollowDistance={false}
|
||||
imageOverlay={formatShort(Math.floor((amount?.amount ?? 0) * (v.weight / total)))}
|
||||
/>
|
||||
))}
|
||||
|
@ -8,6 +8,7 @@ import ProfileImage from "./ProfileImage";
|
||||
import { UserWebsiteLink } from "./UserWebsiteLink";
|
||||
import Text from "Element/Text";
|
||||
import { useEffect, useState } from "react";
|
||||
import useLogin from "../../Hooks/useLogin";
|
||||
|
||||
interface RectElement {
|
||||
getBoundingClientRect(): {
|
||||
@ -35,6 +36,7 @@ export function ProfileCard({
|
||||
}) {
|
||||
const [showProfileMenu, setShowProfileMenu] = useState(false);
|
||||
const [t, setT] = useState<ReturnType<typeof setTimeout>>();
|
||||
const { publicKey: myPublicKey } = useLogin(s => ({ publicKey: s.publicKey }));
|
||||
|
||||
useEffect(() => {
|
||||
if (show) {
|
||||
@ -60,14 +62,14 @@ export function ProfileCard({
|
||||
align="end">
|
||||
<div className="flex flex-col g8">
|
||||
<div className="flex justify-between">
|
||||
<ProfileImage pubkey={""} profile={user} showProfileCard={false} link="" />
|
||||
<ProfileImage pubkey={pubkey} profile={user} showProfileCard={false} link="" />
|
||||
<div className="flex g8">
|
||||
{/*<button type="button" onClick={() => {
|
||||
LoginStore.loginWithPubkey(pubkey, LoginSessionType.PublicKey, undefined, undefined, undefined, true);
|
||||
}}>
|
||||
<FormattedMessage defaultMessage="Stalk" />
|
||||
</button>*/}
|
||||
<FollowButton pubkey={pubkey} />
|
||||
{myPublicKey !== pubkey && <FollowButton pubkey={pubkey} />}
|
||||
</div>
|
||||
</div>
|
||||
<Text
|
||||
|
@ -8,11 +8,11 @@ import classNames from "classnames";
|
||||
|
||||
import Avatar from "Element/User/Avatar";
|
||||
import Nip05 from "Element/User/Nip05";
|
||||
import useLogin from "Hooks/useLogin";
|
||||
import Icon from "Icons/Icon";
|
||||
import DisplayName from "./DisplayName";
|
||||
import { ProfileLink } from "./ProfileLink";
|
||||
import { ProfileCard } from "./ProfileCard";
|
||||
import SocialGraph from "../../SocialGraph/SocialGraph";
|
||||
|
||||
export interface ProfileImageProps {
|
||||
pubkey: HexKey;
|
||||
@ -27,7 +27,7 @@ export interface ProfileImageProps {
|
||||
size?: number;
|
||||
onClick?: (e: React.MouseEvent) => void;
|
||||
imageOverlay?: ReactNode;
|
||||
showFollowingMark?: boolean;
|
||||
showFollowDistance?: boolean;
|
||||
icons?: ReactNode;
|
||||
showProfileCard?: boolean;
|
||||
}
|
||||
@ -45,14 +45,13 @@ export default function ProfileImage({
|
||||
size,
|
||||
imageOverlay,
|
||||
onClick,
|
||||
showFollowingMark = true,
|
||||
showFollowDistance = true,
|
||||
icons,
|
||||
showProfileCard,
|
||||
}: ProfileImageProps) {
|
||||
const user = useUserProfile(profile ? "" : pubkey) ?? profile;
|
||||
const nip05 = defaultNip ? defaultNip : user?.nip05;
|
||||
const { follows } = useLogin();
|
||||
const doesFollow = follows.item.includes(pubkey);
|
||||
const followDistance = SocialGraph.getFollowDistance(pubkey);
|
||||
const [ref, hovering] = useHover<HTMLDivElement>();
|
||||
|
||||
function handleClick(e: React.MouseEvent) {
|
||||
@ -63,6 +62,12 @@ export default function ProfileImage({
|
||||
}
|
||||
|
||||
function inner() {
|
||||
let followDistanceColor = "";
|
||||
if (followDistance <= 1) {
|
||||
followDistanceColor = "success";
|
||||
} else if (followDistance === 2 && SocialGraph.followedByFriendsCount(pubkey) >= 10) {
|
||||
followDistanceColor = "text-nostr-orange";
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="avatar-wrapper" ref={ref}>
|
||||
@ -72,12 +77,12 @@ export default function ProfileImage({
|
||||
size={size}
|
||||
imageOverlay={imageOverlay}
|
||||
icons={
|
||||
(doesFollow && showFollowingMark) || icons ? (
|
||||
(followDistance <= 2 && showFollowDistance) || icons ? (
|
||||
<>
|
||||
{icons}
|
||||
{showFollowingMark && (
|
||||
{showFollowDistance && (
|
||||
<div className="icon-circle">
|
||||
<Icon name="check" className="success" size={10} />
|
||||
<Icon name="check" className={followDistanceColor} size={10} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
Reference in New Issue
Block a user