v2: global player, infinite scroll, image picker, threaded comments

This commit is contained in:
khannurien
2026-03-21 13:55:22 +00:00
parent be426eb150
commit 7c098e7c4c
48 changed files with 4346 additions and 711 deletions

View File

@@ -1,4 +1,6 @@
import { useContext } from "react";
import type { RichContent } from "../model.ts";
import { PlayerContext } from "../contexts/PlayerContext.ts";
interface RichContentCardProps {
richContent: RichContent;
@@ -8,6 +10,8 @@ interface RichContentCardProps {
export default function RichContentCard(
{ richContent, compact = false }: RichContentCardProps,
) {
const { play } = useContext(PlayerContext);
if (compact) {
return (
<a
@@ -33,14 +37,34 @@ export default function RichContentCard(
);
}
return (
<a
href={richContent.url}
target="_blank"
rel="noopener noreferrer"
className={`rich-content-card rich-content-card--${richContent.type}`}
>
{richContent.thumbnailUrl && (
const canPlay = !!richContent.embedUrl;
const thumbnail = richContent.thumbnailUrl && (
canPlay
? (
<button
type="button"
className="rich-content-thumbnail-btn"
onClick={() =>
play({
embedUrl: richContent.embedUrl!,
title: richContent.title,
type: richContent.type,
})}
aria-label="Play"
>
<img
src={richContent.thumbnailUrl}
alt={richContent.title ?? ""}
className="rich-content-thumbnail"
onError={(e) => {
(e.target as HTMLImageElement).style.display = "none";
}}
/>
<span className="rich-content-play-overlay"></span>
</button>
)
: (
<img
src={richContent.thumbnailUrl}
alt={richContent.title ?? ""}
@@ -49,8 +73,18 @@ export default function RichContentCard(
(e.target as HTMLImageElement).style.display = "none";
}}
/>
)}
<div className="rich-content-body">
)
);
return (
<div className={`rich-content-card rich-content-card--${richContent.type}`}>
{thumbnail}
<a
href={richContent.url}
target="_blank"
rel="noopener noreferrer"
className="rich-content-body"
>
{richContent.siteName && (
<span className="rich-content-badge">{richContent.siteName}</span>
)}
@@ -58,10 +92,12 @@ export default function RichContentCard(
<p className="rich-content-title">{richContent.title}</p>
)}
{richContent.description && (
<p className="rich-content-description">{richContent.description}</p>
<p className="rich-content-description">
{richContent.description}
</p>
)}
<span className="rich-content-url">{richContent.url}</span>
</div>
</a>
</a>
</div>
);
}