forked from Kieran/zap.stream
refactor: cleanup
This commit is contained in:
parent
08d554aa8f
commit
45ee55a4c1
@ -39,6 +39,3 @@
|
|||||||
.collapsed-event-header svg {
|
.collapsed-event-header svg {
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.expanded-event {
|
|
||||||
}
|
|
||||||
|
@ -67,12 +67,7 @@ export function CollapsibleEvent({ link }: { link: NostrLink }) {
|
|||||||
</Collapsible.Trigger>
|
</Collapsible.Trigger>
|
||||||
</div>
|
</div>
|
||||||
<Collapsible.Content>
|
<Collapsible.Content>
|
||||||
{open && event && (
|
{open && event && <NostrEvent ev={event} />}
|
||||||
<div className="expanded-event">
|
|
||||||
{" "}
|
|
||||||
<NostrEvent ev={event} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Collapsible.Content>
|
</Collapsible.Content>
|
||||||
</Collapsible.Root>
|
</Collapsible.Root>
|
||||||
);
|
);
|
||||||
|
@ -18,16 +18,3 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
line-height: 29px; /* 161.111% */
|
line-height: 29px; /* 161.111% */
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown img:not(.emoji):not(.note-avatar) {
|
|
||||||
max-height: 720px;
|
|
||||||
margin-top: 8px;
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown video {
|
|
||||||
width: 100%;
|
|
||||||
aspect-ratio: 4/3;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
@ -4,17 +4,12 @@ import { useMemo } from "react";
|
|||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
|
|
||||||
import { HyperText } from "element/hypertext";
|
import { HyperText } from "element/hypertext";
|
||||||
import {
|
import { transformText, type Fragment } from "element/text";
|
||||||
transformText,
|
|
||||||
type Fragment,
|
|
||||||
type NostrComponents,
|
|
||||||
} from "element/text";
|
|
||||||
import type { Tags } from "types";
|
import type { Tags } from "types";
|
||||||
|
|
||||||
interface MarkdownProps {
|
interface MarkdownProps {
|
||||||
content: string;
|
content: string;
|
||||||
tags?: Tags;
|
tags?: Tags;
|
||||||
customComponents?: NostrComponents;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LinkProps {
|
interface LinkProps {
|
||||||
@ -26,36 +21,20 @@ interface ComponentProps {
|
|||||||
children?: Array<Fragment>;
|
children?: Array<Fragment>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Markdown({
|
export function Markdown({ content, tags = [] }: MarkdownProps) {
|
||||||
content,
|
|
||||||
tags = [],
|
|
||||||
customComponents,
|
|
||||||
}: MarkdownProps) {
|
|
||||||
const components = useMemo(() => {
|
const components = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
li: ({ children, ...props }: ComponentProps) => {
|
li: ({ children, ...props }: ComponentProps) => {
|
||||||
return (
|
return children && <li {...props}>{transformText(children, tags)}</li>;
|
||||||
children && (
|
|
||||||
<li {...props}>
|
|
||||||
{transformText(children, tags, customComponents)}
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
td: ({ children }: ComponentProps) => {
|
td: ({ children }: ComponentProps) => {
|
||||||
return (
|
return children && <td>{transformText(children, tags)}</td>;
|
||||||
children && <td>{transformText(children, tags, customComponents)}</td>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
th: ({ children }: ComponentProps) => {
|
th: ({ children }: ComponentProps) => {
|
||||||
return (
|
return children && <th>{transformText(children, tags)}</th>;
|
||||||
children && <th>{transformText(children, tags, customComponents)}</th>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
p: ({ children }: ComponentProps) => {
|
p: ({ children }: ComponentProps) => {
|
||||||
return (
|
return children && <p>{transformText(children, tags)}</p>;
|
||||||
children && <p>{transformText(children, tags, customComponents)}</p>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
a: ({ href, children }: LinkProps) => {
|
a: ({ href, children }: LinkProps) => {
|
||||||
return href && <HyperText link={href}>{children}</HyperText>;
|
return href && <HyperText link={href}>{children}</HyperText>;
|
||||||
|
@ -174,73 +174,3 @@
|
|||||||
.stream-card {
|
.stream-card {
|
||||||
max-width: 343px;
|
max-width: 343px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-zappers-card .top-zappers-leaderboard {
|
|
||||||
border: 1px solid;
|
|
||||||
padding: 4px 8px;
|
|
||||||
border-radius: 12px;
|
|
||||||
border-color: var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-zappers-card .top-zapper-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-zapper-container .zap-amount {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-zapper-container .top-zapper-amount {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-zappers-card .top-zappers-leaderboard {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-zapper-container.first .profile {
|
|
||||||
background: var(--gradient-purple);
|
|
||||||
background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-zapper-container.second .profile {
|
|
||||||
background: var(--gradient-yellow);
|
|
||||||
background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-zapper-container.third .profile {
|
|
||||||
background: var(--gradient-orange);
|
|
||||||
background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-zapper-container.live .profile {
|
|
||||||
background-size: 300% 300%;
|
|
||||||
animation: animatedgradient 3s ease alternate infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes animatedgradient {
|
|
||||||
0% {
|
|
||||||
background-position: 0% 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
background-position: 100% 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
background-position: 0% 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -12,16 +12,12 @@ import { Icon } from "element/icon";
|
|||||||
import { ExternalLink } from "element/external-link";
|
import { ExternalLink } from "element/external-link";
|
||||||
import { FileUploader } from "element/file-uploader";
|
import { FileUploader } from "element/file-uploader";
|
||||||
import { Markdown } from "element/markdown";
|
import { Markdown } from "element/markdown";
|
||||||
import { Profile } from "element/profile";
|
|
||||||
import { useLogin } from "hooks/login";
|
import { useLogin } from "hooks/login";
|
||||||
import { useCards, useUserCards } from "hooks/cards";
|
import { useCards, useUserCards } from "hooks/cards";
|
||||||
import { useZaps } from "hooks/zaps";
|
|
||||||
import useTopZappers from "hooks/top-zappers";
|
|
||||||
import { CARD, USER_CARDS } from "const";
|
import { CARD, USER_CARDS } from "const";
|
||||||
import { toTag, findTag } from "utils";
|
import { toTag, findTag } from "utils";
|
||||||
import { Login, System } from "index";
|
import { Login, System } from "index";
|
||||||
import type { Tags } from "types";
|
import type { Tags } from "types";
|
||||||
import { formatSats } from "number";
|
|
||||||
|
|
||||||
interface CardType {
|
interface CardType {
|
||||||
identifier: string;
|
identifier: string;
|
||||||
@ -430,14 +426,12 @@ export function StreamCardEditor({ pubkey, tags }: StreamCardEditorProps) {
|
|||||||
|
|
||||||
interface StreamCardsProps {
|
interface StreamCardsProps {
|
||||||
host: string;
|
host: string;
|
||||||
isLive: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ReadOnlyStreamCards({ host, isLive }: StreamCardsProps) {
|
export function ReadOnlyStreamCards({ host }: StreamCardsProps) {
|
||||||
const cards = useCards(host);
|
const cards = useCards(host);
|
||||||
return (
|
return (
|
||||||
<div className="stream-cards">
|
<div className="stream-cards">
|
||||||
{cards.length === 99 && <TopZappers host={host} isLive={isLive} />}
|
|
||||||
{cards.map((ev) => (
|
{cards.map((ev) => (
|
||||||
<Card cards={cards} key={ev!.id} ev={ev!} />
|
<Card cards={cards} key={ev!.id} ev={ev!} />
|
||||||
))}
|
))}
|
||||||
@ -445,42 +439,7 @@ export function ReadOnlyStreamCards({ host, isLive }: StreamCardsProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TopZappersProps {
|
export function StreamCards({ host }: StreamCardsProps) {
|
||||||
host: string;
|
|
||||||
isLive: boolean;
|
|
||||||
n?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function TopZappers({ host, isLive, n = 5 }: TopZappersProps) {
|
|
||||||
const zaps = useZaps(host);
|
|
||||||
const topZappers = useTopZappers(zaps);
|
|
||||||
return topZappers.length > 0 ? (
|
|
||||||
<div className="stream-card top-zappers-card">
|
|
||||||
<h1 className="card-title">Top Zappers</h1>
|
|
||||||
<div className="top-zappers-leaderboard">
|
|
||||||
{topZappers
|
|
||||||
.filter((z) => z.pubkey !== "anon")
|
|
||||||
.slice(0, n)
|
|
||||||
.map((z, idx) => (
|
|
||||||
<div
|
|
||||||
className={`top-zapper-container ${idx === 0 ? "first" : ""} ${
|
|
||||||
idx === 1 ? "second" : ""
|
|
||||||
} ${idx === 2 ? "third" : ""}
|
|
||||||
${isLive && idx < 3 ? "live" : ""}`}
|
|
||||||
>
|
|
||||||
<Profile pubkey={z.pubkey} />
|
|
||||||
<div className="zap-amount">
|
|
||||||
<Icon name="zap-filled" className="zap-icon" />
|
|
||||||
<p className="top-zapper-amount">{formatSats(z.total)}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function StreamCards({ host, isLive }: StreamCardsProps) {
|
|
||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
const canEdit = login?.pubkey === host;
|
const canEdit = login?.pubkey === host;
|
||||||
return (
|
return (
|
||||||
@ -488,7 +447,7 @@ export function StreamCards({ host, isLive }: StreamCardsProps) {
|
|||||||
{canEdit ? (
|
{canEdit ? (
|
||||||
<StreamCardEditor tags={login.cards.tags} pubkey={login.pubkey} />
|
<StreamCardEditor tags={login.cards.tags} pubkey={login.pubkey} />
|
||||||
) : (
|
) : (
|
||||||
<ReadOnlyStreamCards isLive={isLive} host={host} />
|
<ReadOnlyStreamCards host={host} />
|
||||||
)}
|
)}
|
||||||
</DndProvider>
|
</DndProvider>
|
||||||
);
|
);
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
.text img:not(.emoji):not(.note-avatar) {
|
|
||||||
max-height: 720px;
|
|
||||||
margin-top: 8px;
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text video {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 8px;
|
|
||||||
aspect-ratio: 4/3;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
@ -1,4 +1,3 @@
|
|||||||
import "./text.css";
|
|
||||||
import { useMemo, type ReactNode, type FunctionComponent } from "react";
|
import { useMemo, type ReactNode, type FunctionComponent } from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -260,13 +260,6 @@ div.paper {
|
|||||||
margin: 6px;
|
margin: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-trigger {
|
|
||||||
font-size: 15px;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ctx-menu {
|
.ctx-menu {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
@ -3,9 +3,6 @@ import { parseNostrLink, TaggedRawEvent } from "@snort/system";
|
|||||||
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
||||||
import { Helmet } from "react-helmet";
|
import { Helmet } from "react-helmet";
|
||||||
|
|
||||||
import { NostrEvent } from "@snort/system";
|
|
||||||
import { useUserProfile } from "@snort/system-react";
|
|
||||||
|
|
||||||
import { LiveVideoPlayer } from "element/live-video-player";
|
import { LiveVideoPlayer } from "element/live-video-player";
|
||||||
import {
|
import {
|
||||||
createNostrLink,
|
createNostrLink,
|
||||||
@ -20,10 +17,13 @@ import { useLogin } from "hooks/login";
|
|||||||
import { useZapGoal } from "hooks/goals";
|
import { useZapGoal } from "hooks/goals";
|
||||||
import { StreamState, System } from "index";
|
import { StreamState, System } from "index";
|
||||||
import { SendZapsDialog } from "element/send-zap";
|
import { SendZapsDialog } from "element/send-zap";
|
||||||
|
import { NostrEvent } from "@snort/system";
|
||||||
|
import { useUserProfile } from "@snort/system-react";
|
||||||
import { NewStreamDialog } from "element/new-stream";
|
import { NewStreamDialog } from "element/new-stream";
|
||||||
import { Tags } from "element/tags";
|
import { Tags } from "element/tags";
|
||||||
import { StatePill } from "element/state-pill";
|
import { StatePill } from "element/state-pill";
|
||||||
import { StreamCards } from "element/stream-cards";
|
import { StreamCards } from "element/stream-cards";
|
||||||
|
import { formatSats } from "number";
|
||||||
import { StreamTimer } from "element/stream-time";
|
import { StreamTimer } from "element/stream-time";
|
||||||
import { ShareMenu } from "element/share-menu";
|
import { ShareMenu } from "element/share-menu";
|
||||||
import {
|
import {
|
||||||
@ -31,7 +31,6 @@ import {
|
|||||||
isContentWarningAccepted,
|
isContentWarningAccepted,
|
||||||
} from "element/content-warning";
|
} from "element/content-warning";
|
||||||
import { useCurrentStreamFeed } from "hooks/current-stream-feed";
|
import { useCurrentStreamFeed } from "hooks/current-stream-feed";
|
||||||
import { formatSats } from "number";
|
|
||||||
|
|
||||||
function ProfileInfo({ ev, goal }: { ev?: NostrEvent; goal?: TaggedRawEvent }) {
|
function ProfileInfo({ ev, goal }: { ev?: NostrEvent; goal?: TaggedRawEvent }) {
|
||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
@ -157,7 +156,7 @@ export function StreamPage() {
|
|||||||
<div className="video-content">
|
<div className="video-content">
|
||||||
<LiveVideoPlayer stream={stream} poster={image} status={status} />
|
<LiveVideoPlayer stream={stream} poster={image} status={status} />
|
||||||
<ProfileInfo ev={ev} goal={goal} />
|
<ProfileInfo ev={ev} goal={goal} />
|
||||||
<StreamCards host={host} isLive={status === StreamState.Live} />
|
<StreamCards host={host} />
|
||||||
</div>
|
</div>
|
||||||
<LiveChat link={createNostrLink(ev) ?? link} ev={ev} goal={goal} />
|
<LiveChat link={createNostrLink(ev) ?? link} ev={ev} goal={goal} />
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user