reorganize code into smaller files & dirs
This commit is contained in:
84
packages/app/src/Components/LiveStream/LiveEvent.tsx
Normal file
84
packages/app/src/Components/LiveStream/LiveEvent.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import { NostrEvent, NostrLink } from "@snort/system";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import { findTag } from "@/Utils";
|
||||
import ProfileImage from "../User/ProfileImage";
|
||||
import Icon from "@/Components/Icons/Icon";
|
||||
|
||||
export function LiveEvent({ ev }: { ev: NostrEvent }) {
|
||||
const title = findTag(ev, "title");
|
||||
const status = findTag(ev, "status");
|
||||
const starts = Number(findTag(ev, "starts"));
|
||||
const host = ev.tags.find(a => a[0] === "p" && a[3] === "host")?.[1] ?? ev.pubkey;
|
||||
|
||||
function statusLine() {
|
||||
switch (status) {
|
||||
case "live": {
|
||||
return (
|
||||
<div className="flex g4 items-center">
|
||||
<Icon name="signal-01" />
|
||||
<b className="uppercase">
|
||||
<FormattedMessage defaultMessage="Live" id="Dn82AL" />
|
||||
</b>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
case "ended": {
|
||||
return (
|
||||
<b className="uppercase">
|
||||
<FormattedMessage defaultMessage="Ended" id="TP/cMX" />
|
||||
</b>
|
||||
);
|
||||
}
|
||||
case "planned": {
|
||||
return (
|
||||
<b className="uppercase">
|
||||
{new Intl.DateTimeFormat(undefined, { dateStyle: "full", timeStyle: "short" }).format(
|
||||
new Date(starts * 1000),
|
||||
)}
|
||||
</b>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cta() {
|
||||
const link = `https://zap.stream/${NostrLink.fromEvent(ev).encode()}`;
|
||||
switch (status) {
|
||||
case "live": {
|
||||
return (
|
||||
<Link to={link} target="_blank">
|
||||
<button className="nowrap">
|
||||
<FormattedMessage defaultMessage="Join Stream" id="GQPtfk" />
|
||||
</button>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
case "ended": {
|
||||
if (findTag(ev, "recording")) {
|
||||
return (
|
||||
<Link to={link} target="_blank">
|
||||
<button className="nowrap">
|
||||
<FormattedMessage defaultMessage="Watch Replay" id="6/hB3S" />
|
||||
</button>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="sm:flex g12 br p24 bg-primary items-center">
|
||||
<div>
|
||||
<ProfileImage pubkey={host} showUsername={false} size={56} />
|
||||
</div>
|
||||
<div className="flex flex-col g8 grow">
|
||||
<div className="font-semibold text-3xl">{title}</div>
|
||||
<div>{statusLine()}</div>
|
||||
</div>
|
||||
<div>{cta()}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
54
packages/app/src/Components/LiveStream/LiveStreams.css
Normal file
54
packages/app/src/Components/LiveStream/LiveStreams.css
Normal file
@ -0,0 +1,54 @@
|
||||
.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;
|
||||
}
|
58
packages/app/src/Components/LiveStream/LiveStreams.tsx
Normal file
58
packages/app/src/Components/LiveStream/LiveStreams.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import "./LiveStreams.css";
|
||||
import { NostrEvent, NostrLink } from "@snort/system";
|
||||
import { findTag } from "@/Utils";
|
||||
import { CSSProperties, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import useImgProxy from "@/Hooks/useImgProxy";
|
||||
import Icon from "@/Components/Icons/Icon";
|
||||
|
||||
export function LiveStreams({ evs }: { evs: Array<NostrEvent> }) {
|
||||
const streams = useMemo(() => {
|
||||
return [...evs].sort((a, b) => {
|
||||
const aStarts = Number(findTag(a, "starts") ?? a.created_at);
|
||||
const bStarts = Number(findTag(b, "starts") ?? b.created_at);
|
||||
return aStarts > bStarts ? -1 : 1;
|
||||
});
|
||||
}, [evs]);
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
function LiveStreamEvent({ ev }: { ev: NostrEvent }) {
|
||||
const { proxy } = useImgProxy();
|
||||
const title = findTag(ev, "title");
|
||||
const image = findTag(ev, "image");
|
||||
const status = findTag(ev, "status");
|
||||
|
||||
const link = NostrLink.fromEvent(ev).encode(CONFIG.eventLinkPrefix);
|
||||
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>
|
||||
</div>
|
||||
<div>{title}</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user