From 73957e65107f6177b62fd7d1dc77c15a3cbf9ae4 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Fri, 10 Feb 2023 12:12:11 +0100 Subject: [PATCH] count in profile page --- packages/app/src/Element/BlockList.tsx | 37 ++------- packages/app/src/Element/Copy.tsx | 2 +- packages/app/src/Element/FollowersList.tsx | 27 ------- packages/app/src/Element/FollowsList.tsx | 24 ------ packages/app/src/Element/FollowsYou.tsx | 20 +---- packages/app/src/Element/MutedList.tsx | 10 +-- packages/app/src/Element/Nip05.css | 1 + packages/app/src/Element/Nip05.tsx | 27 +++---- packages/app/src/Element/Note.css | 5 +- packages/app/src/Element/RelaysMetadata.css | 9 +++ packages/app/src/Element/Tabs.css | 19 +++-- packages/app/src/Element/Tabs.tsx | 3 + packages/app/src/Feed/FollowersFeed.ts | 11 ++- packages/app/src/Feed/FollowsFeed.ts | 25 ++++-- packages/app/src/Feed/MuteList.ts | 14 +++- packages/app/src/Feed/ZapsFeed.ts | 16 +++- packages/app/src/Icons/Badge.tsx | 15 ++++ packages/app/src/Pages/Layout.css | 7 +- packages/app/src/Pages/ProfilePage.css | 31 ++++---- packages/app/src/Pages/ProfilePage.tsx | 88 ++++++++++----------- packages/app/src/Pages/messages.ts | 12 ++- packages/app/src/index.css | 21 +++-- 22 files changed, 205 insertions(+), 219 deletions(-) delete mode 100644 packages/app/src/Element/FollowersList.tsx delete mode 100644 packages/app/src/Element/FollowsList.tsx create mode 100644 packages/app/src/Icons/Badge.tsx diff --git a/packages/app/src/Element/BlockList.tsx b/packages/app/src/Element/BlockList.tsx index 33e07e61..bcd5f3a5 100644 --- a/packages/app/src/Element/BlockList.tsx +++ b/packages/app/src/Element/BlockList.tsx @@ -1,42 +1,15 @@ -import { FormattedMessage } from "react-intl"; -import MuteButton from "Element/MuteButton"; import BlockButton from "Element/BlockButton"; import ProfilePreview from "Element/ProfilePreview"; import useModeration from "Hooks/useModeration"; -import messages from "./messages"; - -interface BlockListProps { - variant: "muted" | "blocked"; -} - -export default function BlockList({ variant }: BlockListProps) { - const { blocked, muted } = useModeration(); +export default function BlockList() { + const { blocked } = useModeration(); return (
- {variant === "muted" && ( - <> -

- -

- {muted.map(a => { - return } pubkey={a} options={{ about: false }} key={a} />; - })} - - )} - {variant === "blocked" && ( - <> -

- -

- {blocked.map(a => { - return ( - } pubkey={a} options={{ about: false }} key={a} /> - ); - })} - - )} + {blocked.map(a => { + return } pubkey={a} options={{ about: false }} key={a} />; + })}
); } diff --git a/packages/app/src/Element/Copy.tsx b/packages/app/src/Element/Copy.tsx index cc3f6765..19f79cb1 100644 --- a/packages/app/src/Element/Copy.tsx +++ b/packages/app/src/Element/Copy.tsx @@ -16,7 +16,7 @@ export default function Copy({ text, maxSize = 32 }: CopyProps) {
copy(text)}> {trimmed} - {copied ? : } + {copied ? : }
); diff --git a/packages/app/src/Element/FollowersList.tsx b/packages/app/src/Element/FollowersList.tsx deleted file mode 100644 index ca19076a..00000000 --- a/packages/app/src/Element/FollowersList.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useMemo } from "react"; -import { useIntl } from "react-intl"; - -import useFollowersFeed from "Feed/FollowersFeed"; -import { HexKey } from "@snort/nostr"; -import { EventKind } from "@snort/nostr"; -import FollowListBase from "Element/FollowListBase"; - -import messages from "./messages"; - -export interface FollowersListProps { - pubkey: HexKey; -} - -export default function FollowersList({ pubkey }: FollowersListProps) { - const { formatMessage } = useIntl(); - const feed = useFollowersFeed(pubkey); - - const pubkeys = useMemo(() => { - const contactLists = feed?.store.notes.filter( - a => a.kind === EventKind.ContactList && a.tags.some(b => b[0] === "p" && b[1] === pubkey) - ); - return [...new Set(contactLists?.map(a => a.pubkey))]; - }, [feed, pubkey]); - - return ; -} diff --git a/packages/app/src/Element/FollowsList.tsx b/packages/app/src/Element/FollowsList.tsx deleted file mode 100644 index 39090733..00000000 --- a/packages/app/src/Element/FollowsList.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { useMemo } from "react"; -import { useIntl } from "react-intl"; - -import useFollowsFeed from "Feed/FollowsFeed"; -import { HexKey } from "@snort/nostr"; -import FollowListBase from "Element/FollowListBase"; -import { getFollowers } from "Feed/FollowsFeed"; - -import messages from "./messages"; - -export interface FollowsListProps { - pubkey: HexKey; -} - -export default function FollowsList({ pubkey }: FollowsListProps) { - const feed = useFollowsFeed(pubkey); - const { formatMessage } = useIntl(); - - const pubkeys = useMemo(() => { - return getFollowers(feed.store, pubkey); - }, [feed, pubkey]); - - return ; -} diff --git a/packages/app/src/Element/FollowsYou.tsx b/packages/app/src/Element/FollowsYou.tsx index 54432c69..8dc1fd6f 100644 --- a/packages/app/src/Element/FollowsYou.tsx +++ b/packages/app/src/Element/FollowsYou.tsx @@ -1,29 +1,13 @@ import "./FollowsYou.css"; -import { useMemo } from "react"; -import { useSelector } from "react-redux"; import { useIntl } from "react-intl"; -import { HexKey } from "@snort/nostr"; -import { RootState } from "State/Store"; -import useFollowsFeed from "Feed/FollowsFeed"; -import { getFollowers } from "Feed/FollowsFeed"; - import messages from "./messages"; export interface FollowsYouProps { - pubkey: HexKey; + followsMe: boolean; } -export default function FollowsYou({ pubkey }: FollowsYouProps) { +export default function FollowsYou({ followsMe }: FollowsYouProps) { const { formatMessage } = useIntl(); - const feed = useFollowsFeed(pubkey); - const loginPubKey = useSelector(s => s.login.publicKey); - - const pubkeys = useMemo(() => { - return getFollowers(feed.store, pubkey); - }, [feed, pubkey]); - - const followsMe = loginPubKey ? pubkeys.includes(loginPubKey) : false; - return followsMe ? {formatMessage(messages.FollowsYou)} : null; } diff --git a/packages/app/src/Element/MutedList.tsx b/packages/app/src/Element/MutedList.tsx index 660e2e15..4616182a 100644 --- a/packages/app/src/Element/MutedList.tsx +++ b/packages/app/src/Element/MutedList.tsx @@ -1,23 +1,17 @@ -import { useMemo } from "react"; import { FormattedMessage } from "react-intl"; import { HexKey } from "@snort/nostr"; import MuteButton from "Element/MuteButton"; import ProfilePreview from "Element/ProfilePreview"; -import useMutedFeed, { getMuted } from "Feed/MuteList"; import useModeration from "Hooks/useModeration"; import messages from "./messages"; export interface MutedListProps { - pubkey: HexKey; + pubkeys: HexKey[]; } -export default function MutedList({ pubkey }: MutedListProps) { +export default function MutedList({ pubkeys }: MutedListProps) { const { isMuted, muteAll } = useModeration(); - const feed = useMutedFeed(pubkey); - const pubkeys = useMemo(() => { - return getMuted(feed.store, pubkey); - }, [feed, pubkey]); const hasAllMuted = pubkeys.every(isMuted); return ( diff --git a/packages/app/src/Element/Nip05.css b/packages/app/src/Element/Nip05.css index d7bc21ab..016cb5c5 100644 --- a/packages/app/src/Element/Nip05.css +++ b/packages/app/src/Element/Nip05.css @@ -43,5 +43,6 @@ } .nip05 .badge { + color: var(--highlight); margin: 0.1em 0.2em; } diff --git a/packages/app/src/Element/Nip05.tsx b/packages/app/src/Element/Nip05.tsx index 517859b7..575371ac 100644 --- a/packages/app/src/Element/Nip05.tsx +++ b/packages/app/src/Element/Nip05.tsx @@ -1,9 +1,6 @@ -import { useQuery } from "react-query"; - -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faCircleCheck, faSpinner, faTriangleExclamation } from "@fortawesome/free-solid-svg-icons"; - import "./Nip05.css"; +import { useQuery } from "react-query"; +import Badge from "Icons/Badge"; import { HexKey } from "@snort/nostr"; interface NostrJson { @@ -59,15 +56,17 @@ const Nip05 = ({ nip05, pubkey, verifyNip = true }: Nip05Params) => { return (
ev.stopPropagation()}> - {!isDefaultUser &&
{`${name}@`}
} - - {domain} - - - {isVerified && } - {!isVerified && !couldNotVerify && } - {couldNotVerify && } - + {!isDefaultUser && isVerified &&
{`${name}@`}
} + {isVerified && ( + <> + + {domain} + + + + + + )}
); }; diff --git a/packages/app/src/Element/Note.css b/packages/app/src/Element/Note.css index 53b379c9..23a020eb 100644 --- a/packages/app/src/Element/Note.css +++ b/packages/app/src/Element/Note.css @@ -115,12 +115,12 @@ border-bottom-right-radius: 16px; } -.light .note > .footer .ctx-menu li:hover { +.note > .footer .ctx-menu li:hover { color: white; background: #2a2a2a; } -.note > .footer .ctx-menu li:hover { +.light .note > .footer .ctx-menu li:hover { color: white; background: var(--font-secondary-color); } @@ -151,6 +151,7 @@ .reaction-pill .reaction-pill-number { margin-left: 8px; + font-feature-settings: "tnum"; } .reaction-pill.reacted { diff --git a/packages/app/src/Element/RelaysMetadata.css b/packages/app/src/Element/RelaysMetadata.css index 8bfb2fa2..982edc35 100644 --- a/packages/app/src/Element/RelaysMetadata.css +++ b/packages/app/src/Element/RelaysMetadata.css @@ -13,6 +13,8 @@ .relay-settings { margin-left: auto; + display: flex; + align-items: center; } .relay-settings svg:not(:last-child) { @@ -25,6 +27,13 @@ opacity: 0.3; } +@media (max-width: 520px) { + .relay-settings svg { + width: 16px; + height: 16px; + } +} + .relay-url { font-size: 14px; } diff --git a/packages/app/src/Element/Tabs.css b/packages/app/src/Element/Tabs.css index 539bad04..3b5d71d6 100644 --- a/packages/app/src/Element/Tabs.css +++ b/packages/app/src/Element/Tabs.css @@ -14,16 +14,17 @@ .tab { color: var(--font-tertiary-color); - border: 1px solid var(--font-tertiary-color); + border: 1px solid var(--border-color); border-radius: 16px; - text-align: center; - font-weight: 600; - line-height: 19px; - padding: 8px 12px; font-weight: 600; font-size: 14px; - line-height: 17px; - margin-right: 12px; + padding: 6px 8px; + text-align: center; + font-feature-settings: "tnum"; +} + +.tab:not(:last-of-type) { + margin-right: 8px; } .tab.active { @@ -40,3 +41,7 @@ cursor: not-allowed; pointer-events: none; } + +.tab:hover { + border-color: var(--font-color); +} diff --git a/packages/app/src/Element/Tabs.tsx b/packages/app/src/Element/Tabs.tsx index 661ea67d..f3a0ead8 100644 --- a/packages/app/src/Element/Tabs.tsx +++ b/packages/app/src/Element/Tabs.tsx @@ -1,5 +1,6 @@ import "./Tabs.css"; import useHorizontalScroll from "Hooks/useHorizontalScroll"; +import { CSSProperties } from "react"; export interface Tab { text: string; @@ -18,9 +19,11 @@ interface TabElementProps extends Omit { } export const TabElement = ({ t, tab, setTab }: TabElementProps) => { + const style = { minWidth: `${t.text.length * 0.6}em` } as CSSProperties; return (
!t.disabled && setTab(t)}> {t.text}
diff --git a/packages/app/src/Feed/FollowersFeed.ts b/packages/app/src/Feed/FollowersFeed.ts index 5e80b6c3..f5efa5a2 100644 --- a/packages/app/src/Feed/FollowersFeed.ts +++ b/packages/app/src/Feed/FollowersFeed.ts @@ -13,5 +13,14 @@ export default function useFollowersFeed(pubkey: HexKey) { return x; }, [pubkey]); - return useSubscription(sub); + const followersFeed = useSubscription(sub, { leaveOpen: false, cache: true }); + + const followers = useMemo(() => { + const contactLists = followersFeed?.store.notes.filter( + a => a.kind === EventKind.ContactList && a.tags.some(b => b[0] === "p" && b[1] === pubkey) + ); + return [...new Set(contactLists?.map(a => a.pubkey))]; + }, [followersFeed, pubkey]); + + return followers; } diff --git a/packages/app/src/Feed/FollowsFeed.ts b/packages/app/src/Feed/FollowsFeed.ts index 97e14585..c1b55e19 100644 --- a/packages/app/src/Feed/FollowsFeed.ts +++ b/packages/app/src/Feed/FollowsFeed.ts @@ -1,23 +1,32 @@ import { useMemo } from "react"; -import { HexKey } from "@snort/nostr"; -import { EventKind, Subscriptions } from "@snort/nostr"; -import useSubscription, { NoteStore } from "Feed/Subscription"; +import { useSelector } from "react-redux"; +import { HexKey, TaggedRawEvent, EventKind, Subscriptions } from "@snort/nostr"; + +import useSubscription from "Feed/Subscription"; +import { RootState } from "State/Store"; export default function useFollowsFeed(pubkey: HexKey) { + const { publicKey, follows } = useSelector((s: RootState) => s.login); + const isMe = publicKey === pubkey; + const sub = useMemo(() => { + if (isMe) return null; const x = new Subscriptions(); x.Id = `follows:${pubkey.slice(0, 12)}`; x.Kinds = new Set([EventKind.ContactList]); x.Authors = new Set([pubkey]); - return x; - }, [pubkey]); + }, [isMe, pubkey]); - return useSubscription(sub); + const contactFeed = useSubscription(sub, { leaveOpen: false, cache: true }); + const following = useMemo(() => { + return getFollowing(contactFeed.store.notes ?? [], pubkey); + }, [contactFeed.store.notes]); + return isMe ? follows : following; } -export function getFollowers(feed: NoteStore, pubkey: HexKey) { - const contactLists = feed?.notes.filter(a => a.kind === EventKind.ContactList && a.pubkey === pubkey); +export function getFollowing(notes: TaggedRawEvent[], pubkey: HexKey) { + const contactLists = notes.filter(a => a.kind === EventKind.ContactList && a.pubkey === pubkey); const pTags = contactLists?.map(a => a.tags.filter(b => b[0] === "p").map(c => c[1])); return [...new Set(pTags?.flat())]; } diff --git a/packages/app/src/Feed/MuteList.ts b/packages/app/src/Feed/MuteList.ts index 43d3b20b..ebcb5c8e 100644 --- a/packages/app/src/Feed/MuteList.ts +++ b/packages/app/src/Feed/MuteList.ts @@ -1,12 +1,18 @@ import { useMemo } from "react"; +import { useSelector } from "react-redux"; import { getNewest } from "Util"; import { HexKey, TaggedRawEvent, Lists } from "@snort/nostr"; import { EventKind, Subscriptions } from "@snort/nostr"; import useSubscription, { NoteStore } from "Feed/Subscription"; +import { RootState } from "State/Store"; export default function useMutedFeed(pubkey: HexKey) { + const { publicKey, muted } = useSelector((s: RootState) => s.login); + const isMe = publicKey === pubkey; + const sub = useMemo(() => { + if (isMe) return null; const sub = new Subscriptions(); sub.Id = `muted:${pubkey.slice(0, 12)}`; sub.Kinds = new Set([EventKind.PubkeyLists]); @@ -16,7 +22,13 @@ export default function useMutedFeed(pubkey: HexKey) { return sub; }, [pubkey]); - return useSubscription(sub); + const mutedFeed = useSubscription(sub, { leaveOpen: false, cache: true }); + + const mutedList = useMemo(() => { + return getMuted(mutedFeed.store, pubkey); + }, [mutedFeed.store]); + + return isMe ? muted : mutedList; } export function getMutedKeys(rawNotes: TaggedRawEvent[]): { diff --git a/packages/app/src/Feed/ZapsFeed.ts b/packages/app/src/Feed/ZapsFeed.ts index 1de836e6..a19ccfb5 100644 --- a/packages/app/src/Feed/ZapsFeed.ts +++ b/packages/app/src/Feed/ZapsFeed.ts @@ -1,6 +1,6 @@ import { useMemo } from "react"; -import { HexKey } from "@snort/nostr"; -import { EventKind, Subscriptions } from "@snort/nostr"; +import { HexKey, EventKind, Subscriptions } from "@snort/nostr"; +import { parseZap } from "Element/Zap"; import useSubscription from "./Subscription"; export default function useZapsFeed(pubkey: HexKey) { @@ -12,5 +12,15 @@ export default function useZapsFeed(pubkey: HexKey) { return x; }, [pubkey]); - return useSubscription(sub, { leaveOpen: true, cache: true }); + const zapsFeed = useSubscription(sub, { leaveOpen: false, cache: true }); + + const zaps = useMemo(() => { + const profileZaps = zapsFeed.store.notes + .map(parseZap) + .filter(z => z.valid && z.p === pubkey && z.zapper !== pubkey && !z.e); + profileZaps.sort((a, b) => b.amount - a.amount); + return profileZaps; + }, [zapsFeed]); + + return zaps; } diff --git a/packages/app/src/Icons/Badge.tsx b/packages/app/src/Icons/Badge.tsx new file mode 100644 index 00000000..910ed6d0 --- /dev/null +++ b/packages/app/src/Icons/Badge.tsx @@ -0,0 +1,15 @@ +const Badge = () => { + return ( + + + + ); +}; + +export default Badge; diff --git a/packages/app/src/Pages/Layout.css b/packages/app/src/Pages/Layout.css index 27090666..2f3f0c9c 100644 --- a/packages/app/src/Pages/Layout.css +++ b/packages/app/src/Pages/Layout.css @@ -30,13 +30,18 @@ header .pfp .avatar-wrapper { align-items: center; } +.header-actions .avatar { + width: 40px; + height: 40px; +} + .header-actions .btn-rnd { position: relative; margin-right: 8px; } @media (min-width: 520px) { - .header-actions .btn-rnd { + .header-actions .btn-rnd:last-of-type { margin-right: 16px; } } diff --git a/packages/app/src/Pages/ProfilePage.css b/packages/app/src/Pages/ProfilePage.css index 2718ce43..43cb4db5 100644 --- a/packages/app/src/Pages/ProfilePage.css +++ b/packages/app/src/Pages/ProfilePage.css @@ -231,23 +231,24 @@ margin-left: 4px; } -.icon-title { - font-weight: 600; - font-size: 19px; - line-height: 23px; - display: flex; - align-items: center; - margin-bottom: 22px; +.banner-bg { + width: 1438px; + height: 758px; + position: absolute; + top: -120px; + left: calc(50% - 750px); + background: radial-gradient(circle at top center, rgba(0, 0, 0, 0.7) 0%, #000000 81.25%), var(--img-url); + filter: blur(10px); + z-index: -1; + display: none; } -.icon-title svg { - margin-right: 8px; +.light .banner-bg { + background: radial-gradient(circle at top center, rgba(241, 241, 241, 0.7) 0%, var(--bg-color) 81.25%), var(--img-url); } -.icon-title h3 { - margin: 0; -} - -.icon-title select { - margin-left: auto; +@media (min-width: 1420px) { + .banner-bg { + display: unset; + } } diff --git a/packages/app/src/Pages/ProfilePage.tsx b/packages/app/src/Pages/ProfilePage.tsx index e8633c67..d4931795 100644 --- a/packages/app/src/Pages/ProfilePage.tsx +++ b/packages/app/src/Pages/ProfilePage.tsx @@ -1,5 +1,5 @@ import "./ProfilePage.css"; -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useState, CSSProperties } from "react"; import { useIntl, FormattedMessage } from "react-intl"; import { useSelector } from "react-redux"; import { useNavigate, useParams } from "react-router-dom"; @@ -14,12 +14,16 @@ import Link from "Icons/Link"; import Qr from "Icons/Qr"; import Zap from "Icons/Zap"; import Envelope from "Icons/Envelope"; +import useMutedFeed from "Feed/MuteList"; import useRelaysFeed from "Feed/RelaysFeed"; import usePinnedFeed from "Feed/PinnedFeed"; import useBookmarkFeed from "Feed/BookmarkFeed"; +import useFollowersFeed from "Feed/FollowersFeed"; +import useFollowsFeed from "Feed/FollowsFeed"; import { useUserProfile } from "Feed/ProfileFeed"; +import useModeration from "Hooks/useModeration"; import useZapsFeed from "Feed/ZapsFeed"; -import { default as ZapElement, parseZap } from "Element/Zap"; +import { default as ZapElement } from "Element/Zap"; import FollowButton from "Element/FollowButton"; import { extractLnAddress, parseId, hexToBech32 } from "Util"; import Avatar from "Element/Avatar"; @@ -30,10 +34,9 @@ import Nip05 from "Element/Nip05"; import Copy from "Element/Copy"; import ProfilePreview from "Element/ProfilePreview"; import ProfileImage from "Element/ProfileImage"; -import FollowersList from "Element/FollowersList"; import BlockList from "Element/BlockList"; import MutedList from "Element/MutedList"; -import FollowsList from "Element/FollowsList"; +import FollowsList from "Element/FollowListBase"; import IconButton from "Element/IconButton"; import { RootState } from "State/Store"; import { HexKey, NostrPrefix } from "@snort/nostr"; @@ -62,12 +65,9 @@ export default function ProfilePage() { const user = useUserProfile(id); const loggedOut = useSelector(s => s.login.loggedOut); const loginPubKey = useSelector(s => s.login.publicKey); - const follows = useSelector(s => s.login.follows); const isMe = loginPubKey === id; const [showLnQr, setShowLnQr] = useState(false); const [showProfileQr, setShowProfileQr] = useState(false); - const { notes: pinned, related: pinRelated } = usePinnedFeed(id); - const { notes: bookmarks, related: bookmarkRelated } = useBookmarkFeed(id); const aboutText = user?.about || ""; const about = Text({ content: aboutText, @@ -78,32 +78,36 @@ export default function ProfilePage() { const lnurl = extractLnAddress(user?.lud16 || user?.lud06 || ""); const website_url = user?.website && !user.website.startsWith("http") ? "https://" + user.website : user?.website || ""; + // feeds + const { blocked } = useModeration(); + const { notes: pinned, related: pinRelated } = usePinnedFeed(id); + const { notes: bookmarks, related: bookmarkRelated } = useBookmarkFeed(id); const relays = useRelaysFeed(id); - const zapFeed = useZapsFeed(id); - const zaps = useMemo(() => { - const profileZaps = zapFeed.store.notes.map(parseZap).filter(z => z.valid && z.p === id && !z.e && z.zapper !== id); - profileZaps.sort((a, b) => b.amount - a.amount); - return profileZaps; - }, [zapFeed.store, id]); + const zaps = useZapsFeed(id); const zapsTotal = zaps.reduce((acc, z) => acc + z.amount, 0); - const horizontalScroll = useHorizontalScroll(); + const followers = useFollowersFeed(id); + const follows = useFollowsFeed(id); + const muted = useMutedFeed(id); + // tabs const ProfileTab = { Notes: { text: formatMessage(messages.Notes), value: NOTES }, Reactions: { text: formatMessage(messages.Reactions), value: REACTIONS }, - Followers: { text: formatMessage(messages.Followers), value: FOLLOWERS }, - Follows: { text: formatMessage(messages.Follows), value: FOLLOWS }, - Zaps: { text: formatMessage(messages.Zaps), value: ZAPS }, - Muted: { text: formatMessage(messages.Muted), value: MUTED }, - Blocked: { text: formatMessage(messages.Blocked), value: BLOCKED }, - Relays: { text: formatMessage(messages.Relays), value: RELAYS }, - Bookmarks: { text: formatMessage(messages.Bookmarks), value: BOOKMARKS }, + Followers: { text: formatMessage(messages.FollowersCount, { n: followers.length }), value: FOLLOWERS }, + Follows: { text: formatMessage(messages.FollowsCount, { n: follows.length }), value: FOLLOWS }, + Zaps: { text: formatMessage(messages.ZapsCount, { n: zaps.length }), value: ZAPS }, + Muted: { text: formatMessage(messages.MutedCount, { n: muted.length }), value: MUTED }, + Blocked: { text: formatMessage(messages.BlockedCount, { n: blocked.length }), value: BLOCKED }, + Relays: { text: formatMessage(messages.RelaysCount, { n: relays.length }), value: RELAYS }, + Bookmarks: { text: formatMessage(messages.BookmarksCount, { n: bookmarks.length }), value: BOOKMARKS }, }; const [tab, setTab] = useState(ProfileTab.Notes); const optionalTabs = [ zapsTotal > 0 && ProfileTab.Zaps, relays.length > 0 && ProfileTab.Relays, bookmarks.length > 0 && ProfileTab.Bookmarks, + muted.length > 0 && ProfileTab.Muted, ].filter(a => unwrap(a)) as Tab[]; + const horizontalScroll = useHorizontalScroll(); useEffect(() => { setTab(ProfileTab.Notes); @@ -114,7 +118,7 @@ export default function ProfilePage() {

{user?.display_name || user?.name || "Nostrich"} - +

{user?.nip05 && } @@ -211,29 +215,22 @@ export default function ProfilePage() { } case FOLLOWS: { - if (isMe) { - return ( -
-

- -

- {follows.map(a => ( - - ))} -
- ); - } else { - return ; - } + return ( +
+ {follows.map(a => ( + + ))} +
+ ); } case FOLLOWERS: { - return ; + return ; } case MUTED: { - return isMe ? : ; + return ; } case BLOCKED: { - return isMe ? : null; + return ; } case RELAYS: { return ; @@ -308,20 +305,23 @@ export default function ProfilePage() { } const w = window.document.querySelector(".page")?.clientWidth; + const bannerStyle = user?.banner ? ({ "--img-url": `url(${user.banner})` } as CSSProperties) : {}; return ( <>
+ {user?.banner &&
} {user?.banner && }
{avatar()} {userDetails()}
-
- {[ProfileTab.Notes, ProfileTab.Followers, ProfileTab.Follows, ProfileTab.Muted].map(renderTab)} - - {optionalTabs.map(renderTab)} - {isMe && renderTab(ProfileTab.Blocked)} +
+
+ {[ProfileTab.Notes, ProfileTab.Followers, ProfileTab.Follows].map(renderTab)} + {optionalTabs.map(renderTab)} + {isMe && blocked.length > 0 && renderTab(ProfileTab.Blocked)} +
{tabContent()} diff --git a/packages/app/src/Pages/messages.ts b/packages/app/src/Pages/messages.ts index 4139bce8..b715720b 100644 --- a/packages/app/src/Pages/messages.ts +++ b/packages/app/src/Pages/messages.ts @@ -10,10 +10,15 @@ export default defineMessages({ Notes: { defaultMessage: "Notes" }, Reactions: { defaultMessage: "Reactions" }, Followers: { defaultMessage: "Followers" }, - Follows: { defaultMessage: "Follows" }, + FollowersCount: { defaultMessage: "{n} Followers" }, + Follows: { defaultMessage: "Following" }, + FollowsCount: { defaultMessage: "{n} Following" }, Zaps: { defaultMessage: "Zaps" }, + ZapsCount: { defaultMessage: "{n} Zaps" }, Muted: { defaultMessage: "Muted" }, + MutedCount: { defaultMessage: "{n} Muted" }, Blocked: { defaultMessage: "Blocked" }, + BlockedCount: { defaultMessage: "{n} Blocked" }, Sats: { defaultMessage: "{n} {n, plural, =1 {sat} other {sats}}" }, Following: { defaultMessage: "Following {n}" }, Settings: { defaultMessage: "Settings" }, @@ -36,6 +41,9 @@ export default defineMessages({ Relays: { defaultMessage: "Relays", }, + RelaysCount: { + defaultMessage: "{n} Relays", + }, Bookmarks: { defaultMessage: "Bookmarks" }, - BookmarksCount: { defaultMessage: "Bookmarks ({n})" }, + BookmarksCount: { defaultMessage: "{n} Bookmarks" }, }); diff --git a/packages/app/src/index.css b/packages/app/src/index.css index 15712cd2..aa2c660b 100644 --- a/packages/app/src/index.css +++ b/packages/app/src/index.css @@ -3,6 +3,7 @@ --font-color: #fff; --font-secondary-color: #a7a7a7; --font-tertiary-color: #a3a3a3; + --border-color: rgba(163, 163, 163, 0.3); --font-size: 16px; --font-size-small: 14px; --font-size-tiny: 12px; @@ -39,10 +40,11 @@ } html.light { - --bg-color: #f1f1f1; - --font-color: #57534e; - --font-secondary-color: #7b7b7b; - --font-tertiary-color: #a7a7a7; + --bg-color: #f8f8f8; + --font-color: #27272a; + --font-secondary-color: #71717a; + --font-tertiary-color: #71717a; + --border-color: rgba(167, 167, 167, 0.3); --highlight-light: #16aac1; --highlight: #0284c7; @@ -215,9 +217,8 @@ button.icon:hover { cursor: pointer; color: var(--font-color); user-select: none; - background-color: var(--bg-color); - color: var(--font-color); - border: 1px solid; + background: none; + border: none; display: inline-block; } @@ -230,18 +231,16 @@ button.icon:hover { } .btn.active { - border: 2px solid; - background-color: var(--gray-secondary); color: var(--font-color); font-weight: 700; } .btn.disabled { - color: var(--gray-light); + opacity: 0.3; } .btn:hover { - background-color: var(--gray); + color: var(--highlight); } .btn-sm {