forked from Kieran/zap.stream
Merge pull request 'feat: in-chat mute button' (#76) from in-chat-mute into main
Reviewed-on: Kieran/stream#76 Reviewed-by: Kieran <kieran@noreply.localhost>
This commit is contained in:
commit
877be3d6b6
@ -85,5 +85,8 @@
|
|||||||
<symbol id="face-content" viewBox="0 0 24 24" fill="none">
|
<symbol id="face-content" viewBox="0 0 24 24" fill="none">
|
||||||
<path d="M8 14C8 14 9.5 16 12 16C14.5 16 16 14 16 14M17 9.24C16.605 9.725 16.065 10 15.5 10C14.935 10 14.41 9.725 14 9.24M10 9.24C9.605 9.725 9.065 10 8.5 10C7.935 10 7.41 9.725 7 9.24M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M8 14C8 14 9.5 16 12 16C14.5 16 16 14 16 14M17 9.24C16.605 9.725 16.065 10 15.5 10C14.935 10 14.41 9.725 14 9.24M10 9.24C9.605 9.725 9.065 10 8.5 10C7.935 10 7.41 9.725 7 9.24M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
<symbol id="user-x" viewBox="0 0 24 24" fill="none">
|
||||||
|
<path d="M16.5 16L21.5 21M21.5 16L16.5 21M15.5 3.29076C16.9659 3.88415 18 5.32131 18 7C18 8.67869 16.9659 10.1159 15.5 10.7092M12 15H8C6.13623 15 5.20435 15 4.46927 15.3045C3.48915 15.7105 2.71046 16.4892 2.30448 17.4693C2 18.2044 2 19.1362 2 21M13.5 7C13.5 9.20914 11.7091 11 9.5 11C7.29086 11 5.5 9.20914 5.5 7C5.5 4.79086 7.29086 3 9.5 3C11.7091 3 13.5 4.79086 13.5 7Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</symbol>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@ -13,6 +13,7 @@ import { Icon } from "element/icon";
|
|||||||
import { Emoji as EmojiComponent } from "element/emoji";
|
import { Emoji as EmojiComponent } from "element/emoji";
|
||||||
import { Profile } from "./profile";
|
import { Profile } from "./profile";
|
||||||
import { Text } from "element/text";
|
import { Text } from "element/text";
|
||||||
|
import { useMute } from "element/mute-button";
|
||||||
import { SendZapsDialog } from "element/send-zap";
|
import { SendZapsDialog } from "element/send-zap";
|
||||||
import { CollapsibleEvent } from "element/collapsible";
|
import { CollapsibleEvent } from "element/collapsible";
|
||||||
import { useLogin } from "hooks/login";
|
import { useLogin } from "hooks/login";
|
||||||
@ -55,6 +56,7 @@ export function ChatMessage({
|
|||||||
const emojiRef = useRef(null);
|
const emojiRef = useRef(null);
|
||||||
const isTablet = useMediaQuery("(max-width: 1020px)");
|
const isTablet = useMediaQuery("(max-width: 1020px)");
|
||||||
const isHovering = useHover(ref);
|
const isHovering = useHover(ref);
|
||||||
|
const { mute } = useMute(ev.pubkey);
|
||||||
const [showZapDialog, setShowZapDialog] = useState(false);
|
const [showZapDialog, setShowZapDialog] = useState(false);
|
||||||
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
|
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
|
||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
@ -62,6 +64,8 @@ export function ChatMessage({
|
|||||||
System,
|
System,
|
||||||
inView?.isIntersecting ? ev.pubkey : undefined
|
inView?.isIntersecting ? ev.pubkey : undefined
|
||||||
);
|
);
|
||||||
|
const shouldShowMuteButton =
|
||||||
|
ev.pubkey !== streamer && ev.pubkey != login?.pubkey;
|
||||||
const zapTarget = profile?.lud16 ?? profile?.lud06;
|
const zapTarget = profile?.lud16 ?? profile?.lud06;
|
||||||
const zaps = useMemo(() => {
|
const zaps = useMemo(() => {
|
||||||
return reactions
|
return reactions
|
||||||
@ -132,11 +136,16 @@ export function ChatMessage({
|
|||||||
const topOffset = ref.current?.getBoundingClientRect().top;
|
const topOffset = ref.current?.getBoundingClientRect().top;
|
||||||
const leftOffset = ref.current?.getBoundingClientRect().left;
|
const leftOffset = ref.current?.getBoundingClientRect().left;
|
||||||
|
|
||||||
function pickEmoji(ev: React.MouseEvent) {
|
function pickEmoji(e: React.MouseEvent) {
|
||||||
ev.stopPropagation();
|
e.stopPropagation();
|
||||||
setShowEmojiPicker(!showEmojiPicker);
|
setShowEmojiPicker(!showEmojiPicker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function muteUser(e: React.MouseEvent) {
|
||||||
|
e.stopPropagation();
|
||||||
|
mute();
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
@ -229,6 +238,11 @@ export function ChatMessage({
|
|||||||
<button className="message-zap-button" onClick={pickEmoji}>
|
<button className="message-zap-button" onClick={pickEmoji}>
|
||||||
<Icon name="face" className="message-zap-button-icon" />
|
<Icon name="face" className="message-zap-button-icon" />
|
||||||
</button>
|
</button>
|
||||||
|
{shouldShowMuteButton && (
|
||||||
|
<button className="message-zap-button" onClick={muteUser}>
|
||||||
|
<Icon name="user-x" className="message-zap-button-icon" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
|
import { useMemo } from "react";
|
||||||
import { useLogin } from "hooks/login";
|
import { useLogin } from "hooks/login";
|
||||||
import AsyncButton from "element/async-button";
|
import AsyncButton from "element/async-button";
|
||||||
import { Login, System } from "index";
|
import { Login, System } from "index";
|
||||||
import { MUTED } from "const";
|
import { MUTED } from "const";
|
||||||
|
|
||||||
export function LoggedInMuteButton({ pubkey }: { pubkey: string }) {
|
export function useMute(pubkey: string) {
|
||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
const { tags, content } = login!.muted;
|
const { tags, content } = login!.muted;
|
||||||
const muted = tags.filter((t) => t.at(0) === "p");
|
const muted = useMemo(() => tags.filter((t) => t.at(0) === "p"), [tags]);
|
||||||
const isMuted = muted.find((t) => t.at(1) === pubkey);
|
const isMuted = useMemo(
|
||||||
|
() => muted.find((t) => t.at(1) === pubkey),
|
||||||
|
[pubkey, muted]
|
||||||
|
);
|
||||||
|
|
||||||
async function unmute() {
|
async function unmute() {
|
||||||
const pub = login?.publisher();
|
const pub = login?.publisher();
|
||||||
@ -43,6 +47,12 @@ export function LoggedInMuteButton({ pubkey }: { pubkey: string }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { isMuted, mute, unmute };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LoggedInMuteButton({ pubkey }: { pubkey: string }) {
|
||||||
|
const { isMuted, mute, unmute } = useMute(pubkey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncButton
|
<AsyncButton
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -42,17 +42,19 @@ export function useStreamsFeed(tag?: string) {
|
|||||||
return [];
|
return [];
|
||||||
}, [feed.data]);
|
}, [feed.data]);
|
||||||
|
|
||||||
const live = feedSorted.filter(
|
const live = feedSorted
|
||||||
(a) => findTag(a, "status") === StreamState.Live
|
.filter((a) => findTag(a, "status") === StreamState.Live)
|
||||||
).sort(sortStarts);
|
.sort(sortStarts);
|
||||||
const planned = feedSorted.filter(
|
const planned = feedSorted
|
||||||
(a) => findTag(a, "status") === StreamState.Planned
|
.filter((a) => findTag(a, "status") === StreamState.Planned)
|
||||||
).sort(sortStarts);
|
.sort(sortStarts);
|
||||||
const ended = feedSorted.filter((a) => {
|
const ended = feedSorted
|
||||||
|
.filter((a) => {
|
||||||
const hasEnded = findTag(a, "status") === StreamState.Ended;
|
const hasEnded = findTag(a, "status") === StreamState.Ended;
|
||||||
const recording = findTag(a, "recording") ?? "";
|
const recording = findTag(a, "recording") ?? "";
|
||||||
return hasEnded && recording?.length > 0;
|
return hasEnded && recording?.length > 0;
|
||||||
}).sort(sortCreatedAt);
|
})
|
||||||
|
.sort(sortCreatedAt);
|
||||||
|
|
||||||
return { live, planned, ended };
|
return { live, planned, ended };
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ export enum LoginType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ReplaceableTags {
|
interface ReplaceableTags {
|
||||||
tags: Array<string[]>;
|
tags: Tags;
|
||||||
content?: string;
|
content?: string;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user