diff --git a/package.json b/package.json index b99547c..dd5c780 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@void-cat/api": "^1.0.7", "@webscopeio/react-textarea-autocomplete": "^4.9.2", "buffer": "^6.0.3", + "classnames": "^2.3.2", "emoji-mart": "^5.5.2", "flag-icons": "^6.11.0", "hls.js": "^1.4.6", diff --git a/src/element/avatar.tsx b/src/element/avatar.tsx index 1b28884..b2eefa4 100644 --- a/src/element/avatar.tsx +++ b/src/element/avatar.tsx @@ -1,5 +1,20 @@ import { MetadataCache } from "@snort/system"; +import { HTMLProps, useState } from "react"; +import classNames from "classnames"; +import { getPlaceholder } from "@/utils"; -export function Avatar({ user, avatarClassname }: { user: MetadataCache; avatarClassname: string }) { - return {user?.name; +type AvatarProps = HTMLProps & { size?: number, pubkey: string, user?: MetadataCache }; +export function Avatar({ pubkey, size, user, ...props }: AvatarProps) { + const [failed, setFailed] = useState(false); + const src = user?.picture && !failed ? user.picture : getPlaceholder(pubkey); + return {user?.name setFailed(true)} + style={{ + width: `${size ?? 40}px`, + height: `${size ?? 40}px` + }} />; } diff --git a/src/element/chat-message.tsx b/src/element/chat-message.tsx index 8eb9c1f..30a9c9a 100644 --- a/src/element/chat-message.tsx +++ b/src/element/chat-message.tsx @@ -129,6 +129,7 @@ export function ChatMessage({ <>
@@ -141,14 +142,14 @@ export function ChatMessage({ ) } pubkey={ev.pubkey} - profile={profile} /> +   {(hasReactions || hasZaps) && (
{hasZaps && (
- + {formatSats(totalZaps)}
)} @@ -176,15 +177,15 @@ export function ChatMessage({ style={ isTablet ? { - display: showZapDialog || isHovering ? "flex" : "none", - } + display: showZapDialog || isHovering ? "flex" : "none", + } : { - position: "fixed", - top: topOffset ? topOffset - 12 : 0, - left: leftOffset ? leftOffset - 32 : 0, - opacity: showZapDialog || isHovering ? 1 : 0, - pointerEvents: showZapDialog || isHovering ? "auto" : "none", - } + position: "fixed", + top: topOffset ? topOffset - 12 : 0, + left: leftOffset ? leftOffset - 32 : 0, + opacity: showZapDialog || isHovering ? 1 : 0, + pointerEvents: showZapDialog || isHovering ? "auto" : "none", + } }> {zapTarget && ( .write-message > div:nth-child(1) { - height: 40px; flex-grow: 1; } @@ -72,26 +71,12 @@ line-height: 24px; } -.live-chat .message .profile { - gap: 8px; - font-weight: 600; - float: left; - color: #34d2fe; - margin-right: 8px; -} - -.live-chat .message.streamer .profile { - color: var(--primary); -} - .live-chat .message a { - color: var(--primary); display: inline-flex; } -.live-chat .profile img { - width: 24px; - height: 24px; +.live-chat .message .text a { + color: var(--primary); } .live-chat .messages { @@ -105,10 +90,6 @@ flex-wrap: wrap; } -.live-chat .zap-content a { - color: var(--primary); -} - .top-zappers { display: flex; flex-direction: column; @@ -144,28 +125,6 @@ } } -.top-zapper { - display: flex; - padding: 4px 8px 4px 4px; - align-items: center; - gap: 8px; - border-radius: 49px; - border: 1px solid var(--border, #171717); -} - -.top-zapper .top-zapper-amount { - font-size: 15px; - font-family: Outfit; - font-weight: 700; - line-height: 22px; - margin: 0; -} - -.top-zapper .top-zapper-name { - font-size: 14px; - margin: 0; -} - .zap-container { position: relative; border-radius: 12px; @@ -188,14 +147,6 @@ border-radius: inherit; } -.zap-container .profile { - color: #ff8d2b; -} - -.zap-container .zap-amount { - color: #ff8d2b; -} - .zap-container.big-zap:before { background: linear-gradient(60deg, #2bd9ff, #8c8ded, #f838d9, #f83838, #ff902b, #ddf838); animation: animatedgradient 3s ease alternate infinite; @@ -216,10 +167,6 @@ } } -.zap-content { - margin-top: 8px; -} - .zap-pill { border-radius: 100px; background: rgba(255, 255, 255, 0.1); @@ -231,12 +178,6 @@ gap: 2px; } -.zap-pill-icon { - width: 12px; - height: 12px; - color: #ff8d2b; -} - .message-zap-container { display: flex; padding: 8px; diff --git a/src/element/live-chat.tsx b/src/element/live-chat.tsx index 9b83d69..582a433 100644 --- a/src/element/live-chat.tsx +++ b/src/element/live-chat.tsx @@ -1,6 +1,6 @@ import "./live-chat.css"; import { FormattedMessage } from "react-intl"; -import { EventKind, NostrEvent, NostrLink, ParsedZap } from "@snort/system"; +import { EventKind, NostrEvent, NostrLink, ParsedZap, TaggedNostrEvent } from "@snort/system"; import { useEventReactions } from "@snort/system-react"; import { unixNow } from "@snort/shared"; import { useMemo } from "react"; @@ -80,8 +80,16 @@ export function LiveChat({ const reactions = useEventReactions(link, feed.reactions); const events = useMemo(() => { - return [...feed.messages, ...feed.reactions, ...awards] - .filter(a => a.created_at > started) + const extra = []; + const starts = findTag(ev, "starts"); + if (starts) { + extra.push({ kind: -1, created_at: Number(starts) } as TaggedNostrEvent); + } + const ends = findTag(ev, "ends"); + if (ends) { + extra.push({ kind: -2, created_at: Number(ends) } as TaggedNostrEvent); + } + return [...feed.messages, ...feed.reactions, ...awards, ...extra] .sort((a, b) => b.created_at - a.created_at); }, [feed.messages, feed.reactions, awards]); @@ -118,6 +126,13 @@ export function LiveChat({
{filteredEvents.map(a => { switch (a.kind) { + case -1: + case -2: { + return + {a.kind === -1 ? + : } + ; + } case EventKind.BadgeAward: { return ; } @@ -169,18 +184,18 @@ function ChatZap({ zap }: { zap: ParsedZap }) { return (
-
- +
+ {c}, person: ( ), @@ -188,11 +203,7 @@ function ChatZap({ zap }: { zap: ParsedZap }) { }} />
- {zap.content && ( -
- -
- )} + {zap.content && }
); } diff --git a/src/element/note.css b/src/element/note.css index f88f081..0aaf59d 100644 --- a/src/element/note.css +++ b/src/element/note.css @@ -12,16 +12,6 @@ justify-content: space-between; } -.note .note-header .profile { - font-size: 15px; - font-weight: 600; -} - -.note .note-header .note-avatar { - width: 24px; - height: 24px; -} - .note .note-header .note-link-icon { color: #909090; } diff --git a/src/element/note.tsx b/src/element/note.tsx index ea687ec..74fa89f 100644 --- a/src/element/note.tsx +++ b/src/element/note.tsx @@ -11,7 +11,7 @@ export function Note({ ev }: { ev: NostrEvent }) { return (
- + - {showAvatar && - (pubkey === "anon" ? ( - - ) : ( - {pLoaded?.name - ))} + {showAvatar && } {icon} - {showName && {options?.overrideName ?? pubkey === "anon" ? "Anon" : getName(pubkey, pLoaded)}} + {showName && {isAnon ? (options?.overrideName ?? "Anon") : getName(pubkey, pLoaded)}} ); - return pubkey === "anon" || linkToProfile === false ? ( -
+ const cls = classNames("flex gap-1 items-center align-bottom font-medium", className); + return isAnon || linkToProfile === false ? ( +
{content}
) : ( - + {content} ); diff --git a/src/element/state-pill.tsx b/src/element/state-pill.tsx index 4e79d99..010dd87 100644 --- a/src/element/state-pill.tsx +++ b/src/element/state-pill.tsx @@ -1,12 +1,13 @@ import { HTMLProps } from "react"; import "./state-pill.css"; import { StreamState } from "@/index"; +import classNames from "classnames"; type StatePillProps = { state: StreamState } & HTMLProps; export function StatePill({ state, ...props }: StatePillProps) { return ( - + {state} ); diff --git a/src/element/textarea.tsx b/src/element/textarea.tsx index b66e967..07fba3a 100644 --- a/src/element/textarea.tsx +++ b/src/element/textarea.tsx @@ -33,7 +33,7 @@ const UserItem = (metadata: MetadataCache) => { const { pubkey, display_name, ...rest } = metadata; return (
- +
{display_name || rest.name}
); diff --git a/src/element/top-zappers.tsx b/src/element/top-zappers.tsx index ee4e0dc..330d443 100644 --- a/src/element/top-zappers.tsx +++ b/src/element/top-zappers.tsx @@ -1,27 +1,10 @@ import { ParsedZap } from "@snort/system"; import useTopZappers from "@/hooks/top-zappers"; -import { formatSats } from "@/number"; -import { Icon } from "./icon"; -import { Profile } from "./profile"; +import { ZapperRow } from "./zapper-row"; export function TopZappers({ zaps, limit }: { zaps: ParsedZap[]; limit?: number }) { const zappers = useTopZappers(zaps); - - return ( - <> - {zappers.slice(0, limit ?? 10).map(({ pubkey, total }) => { - return ( -
- {pubkey === "anon" ? ( -

Anon

- ) : ( - - )} - -

{formatSats(total)}

-
- ); - })} - - ); + return zappers.slice(0, limit ?? 10).map(({ pubkey, total }) =>
+ +
); } diff --git a/src/element/write-message.tsx b/src/element/write-message.tsx index 58fd4d8..bd9b131 100644 --- a/src/element/write-message.tsx +++ b/src/element/write-message.tsx @@ -83,7 +83,7 @@ export function WriteMessage({ link, emojiPacks }: { link: NostrLink; emojiPacks return ( <>
-