fix: stream cards rendering
This commit is contained in:
parent
0977e61422
commit
05fab75680
@ -12,7 +12,7 @@ export function Badge({ ev }: { ev: NostrEvent }) {
|
||||
<img className="badge-thumbnail" src={thumb || image} alt={name} />
|
||||
<div className="badge-details">
|
||||
<h4 className="badge-name">{name}</h4>
|
||||
{description?.length > 0 && <p className="badge-description">{description}</p>}
|
||||
{description?.length > 0 && <div className="badge-description">{description}</div>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -60,7 +60,7 @@ export function EmojiPack({ ev }: { ev: NostrEvent }) {
|
||||
{emoji.map(e => {
|
||||
const [, name, image] = e;
|
||||
return (
|
||||
<div className="emoji-definition">
|
||||
<div className="emoji-definition" key={name}>
|
||||
<img alt={name} className="custom-emoji" src={image} />
|
||||
<span className="emoji-name">{name}</span>
|
||||
</div>
|
||||
|
@ -11,6 +11,7 @@ import LiveStreamClip from "./stream/clip";
|
||||
import { ExternalLink } from "./external-link";
|
||||
import { extractStreamInfo } from "@/utils";
|
||||
import LiveVideoPlayer from "./stream/live-video-player";
|
||||
import { HTMLProps } from "react";
|
||||
|
||||
interface EventProps {
|
||||
link: NostrLink;
|
||||
@ -64,9 +65,9 @@ export function NostrEvent({ ev }: { ev: TaggedNostrEvent }) {
|
||||
}
|
||||
}
|
||||
|
||||
export function EventEmbed({ link }: EventProps) {
|
||||
export function EventEmbed({ link, ...props }: EventProps & HTMLProps<HTMLDivElement>) {
|
||||
const event = useEventFeed(link);
|
||||
if (event) {
|
||||
return <NostrEvent ev={event} />;
|
||||
return <NostrEvent ev={event} {...props} />;
|
||||
}
|
||||
}
|
||||
|
@ -14,85 +14,86 @@ interface MarkdownProps {
|
||||
}
|
||||
|
||||
const Markdown = forwardRef<HTMLDivElement, MarkdownProps>((props: MarkdownProps, ref) => {
|
||||
function renderToken(t: Token, key: number): ReactNode {
|
||||
let ctr = 0;
|
||||
function renderToken(t: Token): ReactNode {
|
||||
try {
|
||||
switch (t.type) {
|
||||
case "paragraph": {
|
||||
return <p key={key}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</p>;
|
||||
return <div key={ctr++}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</div>;
|
||||
}
|
||||
case "image": {
|
||||
return <img key={key} src={t.href} />;
|
||||
return <img key={ctr++} src={t.href} />;
|
||||
}
|
||||
case "heading": {
|
||||
switch (t.depth) {
|
||||
case 1:
|
||||
return <h1 key={key}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h1>;
|
||||
return <h1 key={ctr++}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h1>;
|
||||
case 2:
|
||||
return <h2 key={key}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h2>;
|
||||
return <h2 key={ctr++}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h2>;
|
||||
case 3:
|
||||
return <h3 key={key}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h3>;
|
||||
return <h3 key={ctr++}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h3>;
|
||||
case 4:
|
||||
return <h4 key={key}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h4>;
|
||||
return <h4 key={ctr++}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h4>;
|
||||
case 5:
|
||||
return <h5 key={key}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h5>;
|
||||
return <h5 key={ctr++}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h5>;
|
||||
case 6:
|
||||
return <h6 key={key}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h6>;
|
||||
return <h6 key={ctr++}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</h6>;
|
||||
}
|
||||
throw new Error("Invalid heading");
|
||||
}
|
||||
case "codespan": {
|
||||
return <code key={key}>{t.raw}</code>;
|
||||
return <code key={ctr++}>{t.raw}</code>;
|
||||
}
|
||||
case "code": {
|
||||
return <pre key={key}>{t.raw}</pre>;
|
||||
return <pre key={ctr++}>{t.raw}</pre>;
|
||||
}
|
||||
case "br": {
|
||||
return <br key={key} />;
|
||||
return <br key={ctr++} />;
|
||||
}
|
||||
case "hr": {
|
||||
return <hr key={key} />;
|
||||
return <hr key={ctr++} />;
|
||||
}
|
||||
case "blockquote": {
|
||||
return <blockquote key={key}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</blockquote>;
|
||||
return <blockquote key={ctr++}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</blockquote>;
|
||||
}
|
||||
case "link": {
|
||||
return (
|
||||
<HyperText link={t.href} key={key}>
|
||||
<HyperText link={t.href} key={ctr++}>
|
||||
{t.tokens ? t.tokens.map(renderToken) : t.raw}
|
||||
</HyperText>
|
||||
);
|
||||
}
|
||||
case "list": {
|
||||
if (t.ordered) {
|
||||
return <ol key={key}>{t.items.map(renderToken)}</ol>;
|
||||
return <ol key={ctr++}>{t.items.map(renderToken)}</ol>;
|
||||
} else {
|
||||
return <ul key={key}>{t.items.map(renderToken)}</ul>;
|
||||
return <ul key={ctr++}>{t.items.map(renderToken)}</ul>;
|
||||
}
|
||||
}
|
||||
case "list_item": {
|
||||
return <li key={key}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</li>;
|
||||
return <li key={ctr++}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</li>;
|
||||
}
|
||||
case "em": {
|
||||
return <em key={key}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</em>;
|
||||
return <em key={ctr++}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</em>;
|
||||
}
|
||||
case "del": {
|
||||
return <s key={key}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</s>;
|
||||
return <s key={ctr++}>{t.tokens ? t.tokens.map(renderToken) : t.raw}</s>;
|
||||
}
|
||||
case "table": {
|
||||
return (
|
||||
<table className="table-auto border-collapse" key={key}>
|
||||
<table className="table-auto border-collapse" key={ctr++}>
|
||||
<thead>
|
||||
<tr>
|
||||
{(t.header as Tokens.TableCell[]).map((v, h_key) => (
|
||||
<th className="border" key={h_key}>
|
||||
{(t.header as Tokens.TableCell[]).map(v => (
|
||||
<th className="border" key={ctr++}>
|
||||
{v.tokens ? v.tokens.map(renderToken) : v.text}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(t.rows as Tokens.TableCell[][]).map((v, r_key) => (
|
||||
<tr key={r_key}>
|
||||
{(t.rows as Tokens.TableCell[][]).map(v => (
|
||||
<tr key={ctr++}>
|
||||
{v.map((d, d_key) => (
|
||||
<td className="border px-2 py-1" key={d_key}>
|
||||
{d.tokens ? d.tokens.map(renderToken) : d.text}
|
||||
@ -111,7 +112,7 @@ const Markdown = forwardRef<HTMLDivElement, MarkdownProps>((props: MarkdownProps
|
||||
if (props.plainText ?? false) {
|
||||
return t.raw;
|
||||
}
|
||||
return <Text content={t.raw} tags={[]} key={key} />;
|
||||
return <Text content={t.raw} tags={[]} key={ctr++} />;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -37,7 +37,6 @@ export interface SendZapsProps {
|
||||
onFinish: () => void;
|
||||
onTargetReady?: () => void;
|
||||
button?: ReactNode;
|
||||
key?: string;
|
||||
}
|
||||
|
||||
export function SendZaps({ lnurl, pubkey, aTag, eTag, targetName, onFinish, onTargetReady }: SendZapsProps) {
|
||||
@ -216,7 +215,7 @@ export function SendZapsDialog(props: Omit<SendZapsProps, "onFinish">) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [ready, setReady] = useState(false);
|
||||
return (
|
||||
<Fragment key={props.key}>
|
||||
<Fragment>
|
||||
{props.button ? (
|
||||
<div onClick={() => setOpen(true)}>{props.button}</div>
|
||||
) : (
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { NostrLink, NostrPrefix, ParsedFragment, transformText, tryParseNostrLink } from "@snort/system";
|
||||
import { Fragment, FunctionComponent, useMemo } from "react";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import { Emoji } from "./emoji";
|
||||
@ -22,10 +22,11 @@ export function Text({ content, tags, eventComponent, className }: TextProps) {
|
||||
return transformText(content, tags);
|
||||
}, [content, tags]);
|
||||
|
||||
function renderFrag(f: ParsedFragment, key: number) {
|
||||
let ctr = 0;
|
||||
function renderFrag(f: ParsedFragment) {
|
||||
switch (f.type) {
|
||||
case "custom_emoji":
|
||||
return <Emoji name={f.content} url={f.content} key={key} />;
|
||||
return <Emoji name={f.content} url={f.content} key={ctr++} />;
|
||||
case "media":
|
||||
case "link": {
|
||||
if (f.content.startsWith("nostr:")) {
|
||||
@ -36,25 +37,23 @@ export function Text({ content, tags, eventComponent, className }: TextProps) {
|
||||
link.type === NostrPrefix.Address ||
|
||||
link.type === NostrPrefix.Note
|
||||
) {
|
||||
return (
|
||||
<Fragment key={key}>{eventComponent?.({ link })} </Fragment> ?? <EventEmbed link={link} key={key} />
|
||||
);
|
||||
return eventComponent?.({ link }) ?? <EventEmbed link={link} key={ctr++} />;
|
||||
} else {
|
||||
return <Mention pubkey={link.id} key={key} />;
|
||||
return <Mention pubkey={link.id} key={ctr++} />;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
<HyperText link={f.content} key={key}>
|
||||
<HyperText link={f.content} key={ctr++}>
|
||||
{f.content}
|
||||
</HyperText>
|
||||
);
|
||||
}
|
||||
case "mention":
|
||||
return <Mention pubkey={f.content} key={key} />;
|
||||
return <Mention pubkey={f.content} key={ctr++} />;
|
||||
case "hashtag":
|
||||
return (
|
||||
<Link to={`/t/${f.content}`} key={key}>
|
||||
<Link to={`/t/${f.content}`} key={ctr++}>
|
||||
#{f.content}
|
||||
</Link>
|
||||
);
|
||||
@ -63,14 +62,7 @@ export function Text({ content, tags, eventComponent, className }: TextProps) {
|
||||
// LUD-17: https://github.com/lnurl/luds/blob/luds/17.md
|
||||
const url = new URL(f.content);
|
||||
url.protocol = "https:";
|
||||
return (
|
||||
<SendZapsDialog
|
||||
pubkey={undefined}
|
||||
lnurl={url.toString()}
|
||||
button={<Link to={""}>{f.content}</Link>}
|
||||
key={key}
|
||||
/>
|
||||
);
|
||||
return <SendZapsDialog pubkey={undefined} lnurl={url.toString()} button={<Link to={""}>{f.content}</Link>} />;
|
||||
}
|
||||
return f.content;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user