refactor: useRequestBuilder

This commit is contained in:
2024-09-12 16:26:30 +01:00
parent 9eb97701b4
commit e877625923
28 changed files with 195 additions and 205 deletions

View File

@ -1,54 +0,0 @@
.stream-list {
display: flex;
gap: 4px;
overflow-x: auto;
}
.stream-list::-webkit-scrollbar {
height: 6.25px;
}
.stream-event {
display: flex;
padding: 8px 12px;
gap: 8px;
text-decoration: none;
}
.stream-event > div:first-of-type {
border-radius: 8px;
height: 49px;
width: 65px;
background-color: var(--gray-light);
background-image: var(--img);
background-position: center;
background-size: cover;
}
.stream-event span.live {
display: flex;
padding: 4px 6px;
justify-content: center;
align-items: center;
gap: 4px;
border-radius: 9px;
background: var(--live);
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
}
.stream-event .details .reactions {
color: var(--font-secondary-color);
}
.stream-event .details > div:nth-of-type(2) {
width: 100px;
min-width: 0;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
font-size: 16px;
font-weight: 600;
line-height: 24px;
}

View File

@ -1,34 +1,51 @@
import "./LiveStreams.css";
import { unixNow } from "@snort/shared";
import { EventKind, NostrEvent, NostrLink, RequestBuilder } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { useRequestBuilder, useUserProfile } from "@snort/system-react";
import { CSSProperties, useMemo } from "react";
import { FormattedMessage } from "react-intl";
import { Link } from "react-router-dom";
import Icon from "@/Components/Icons/Icon";
import useFollowsControls from "@/Hooks/useFollowControls";
import useImgProxy from "@/Hooks/useImgProxy";
import { findTag } from "@/Utils";
import { Hour } from "@/Utils/Const";
import Avatar from "../User/Avatar";
export function LiveStreams() {
const { followList } = useFollowsControls();
const sub = useMemo(() => {
const since = unixNow() - 60 * 60 * 24;
const rb = new RequestBuilder("follows:streams");
rb.withFilter().kinds([EventKind.LiveEvent]).authors(followList).since(since);
rb.withFilter().kinds([EventKind.LiveEvent]).tag("p", followList).since(since);
if (followList.length > 0) {
rb.withFilter()
.kinds([EventKind.LiveEvent])
.authors(followList)
.since(unixNow() - Hour);
rb.withFilter()
.kinds([EventKind.LiveEvent])
.tag("p", followList)
.since(unixNow() - Hour);
}
return rb;
}, [followList]);
}, [followList.length]);
const streams = useRequestBuilder(sub);
if (streams.length === 0) return null;
return (
<div className="stream-list">
{streams.map(v => (
<LiveStreamEvent ev={v} key={`${v.kind}:${v.pubkey}:${findTag(v, "d")}`} />
))}
<div className="flex mx-2 gap-4 overflow-x-auto sm-hide-scrollbar">
{streams
.filter(a => {
return findTag(a, "status") === "live";
})
.sort((a, b) => {
const sA = Number(findTag(a, "starts"));
const sB = Number(findTag(b, "starts"));
return sA > sB ? -1 : 1;
})
.map(v => (
<LiveStreamEvent ev={v} key={`${v.kind}:${v.pubkey}:${findTag(v, "d")}`} />
))}
</div>
);
}
@ -38,27 +55,33 @@ function LiveStreamEvent({ ev }: { ev: NostrEvent }) {
const title = findTag(ev, "title");
const image = findTag(ev, "image");
const status = findTag(ev, "status");
const viewers = findTag(ev, "current_participants");
const host = ev.tags.find(a => a[0] === "p" && a[3] === "host")?.[1] ?? ev.pubkey;
const hostProfile = useUserProfile(host);
const link = NostrLink.fromEvent(ev).encode(CONFIG.eventLinkPrefix);
const link = NostrLink.fromEvent(ev).encode();
const imageProxy = proxy(image ?? "");
return (
<Link className="stream-event" to={`https://zap.stream/${link}`} target="_blank">
<div
style={
{
"--img": `url(${imageProxy})`,
} as CSSProperties
}></div>
<div className="flex flex-col details">
<div className="flex g2">
<span className="live">{status}</span>
<div className="reaction-pill">
<Icon name="zap" size={24} />
<div className="reaction-pill-number">0</div>
</div>
<Link className="flex gap-2 h-[80px]" to={`https://zap.stream/${link}`} target="_blank">
<div className="relative aspect-video">
<div
className="absolute h-full w-full bg-center bg-cover bg-gray-ultradark rounded-lg"
style={
{
backgroundImage: `url(${imageProxy})`,
} as CSSProperties
}></div>
<div className="absolute left-0 top-7 w-full overflow-hidden">
<div className="whitespace-nowrap px-2 text-ellipsis overflow-hidden text-xs">{title}</div>
</div>
<div className="absolute top-1 left-1 bg-heart rounded-md px-2 uppercase font-bold">{status}</div>
<div className="absolute right-1 top-1">
<Avatar pubkey={host} user={hostProfile} size={25} className="outline outline-2 outline-highlight" />
</div>
<div className="absolute left-1 bottom-1 rounded-md px-2 py-1 text-xs bg-gray font-medium">
<FormattedMessage defaultMessage="{n} viewers" values={{ n: viewers }} />
</div>
<div>{title}</div>
</div>
</Link>
);

View File

@ -11,14 +11,14 @@ import UptimeLabel from "./uptime-label";
export default function RelayUptime({ url }: { url: string }) {
const sub = useMemo(() => {
const u = sanitizeRelayUrl(url);
if (!u) return;
const rb = new RequestBuilder(`uptime`);
rb.withFilter()
.kinds([30_166 as EventKind])
.tag("d", [u])
.since(unixNow() - Day)
.relay(MonitorRelays);
if (u) {
rb.withFilter()
.kinds([30_166 as EventKind])
.tag("d", [u])
.since(unixNow() - Day)
.relay(MonitorRelays);
}
return rb;
}, [url]);