terry-wallet-login #15
@@ -147,12 +147,49 @@ function FileCard({ post, att }: { post: Post; att: Attachment }) {
|
||||
);
|
||||
}
|
||||
|
||||
function MediaGrid({ attachments }: { attachments: Attachment[] }) {
|
||||
const visible = attachments.slice(0, 4);
|
||||
const extra = Math.max(0, attachments.length - visible.length);
|
||||
if (visible.length <= 1) {
|
||||
const src = attachmentPreview(visible[0]);
|
||||
return src ? (
|
||||
function PillDownloadIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="12"
|
||||
height="10"
|
||||
viewBox="0 0 12 10"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M9.84528 3.61663C9.68928 1.5958 8.02426 0 6.00008 0C4.26863 0 2.78232 1.14503 2.30275 2.81502C0.934727 3.29852 0 4.6181 0 6.10918C0 8.034 1.53816 9.60013 3.42862 9.60013H9.00013C10.6544 9.60013 12.0002 8.22993 12.0002 6.54555C12.0002 5.17142 11.113 3.99191 9.84528 3.61663ZM8.0174 5.98132L6.30309 7.7268C6.21952 7.81189 6.1098 7.85465 6.00008 7.85465C5.89037 7.85465 5.78065 7.81189 5.69708 7.7268L3.98277 5.98132C3.8602 5.85652 3.82334 5.66888 3.88977 5.50568C3.9562 5.34291 4.11263 5.23644 4.28577 5.23644H5.14293V3.49096C5.14293 3.00921 5.52693 2.61822 6.00008 2.61822C6.47323 2.61822 6.85724 3.00921 6.85724 3.49096V5.23644H7.71439C7.88754 5.23644 8.04397 5.34291 8.1104 5.50568C8.17683 5.66888 8.13997 5.85652 8.0174 5.98132Z"
|
||||
fill="#A8A9AE"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function MediaSizeChip({ att }: { att: Attachment }) {
|
||||
return (
|
||||
<div className="absolute left-3 top-2.5 z-20 flex h-6 w-[72px] items-center overflow-hidden rounded-full bg-black text-white">
|
||||
<span className="grid h-6 w-6 shrink-0 place-items-center bg-[#545454]">
|
||||
<PillDownloadIcon />
|
||||
</span>
|
||||
<span className="flex h-4 w-12 items-center justify-center text-[10px] font-medium leading-4">
|
||||
{formatBytes(att.sizeBytes)}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function MediaTile({
|
||||
att,
|
||||
showExtra,
|
||||
}: {
|
||||
att: Attachment;
|
||||
showExtra?: number;
|
||||
}) {
|
||||
const src = attachmentPreview(att);
|
||||
const isVideo = att.kind === "video" || att.mime.startsWith("video/");
|
||||
return (
|
||||
<div className="relative h-full w-full overflow-hidden bg-black">
|
||||
{src ? (
|
||||
<img
|
||||
src={src}
|
||||
alt=""
|
||||
@@ -160,44 +197,62 @@ function MediaGrid({ attachments }: { attachments: Attachment[] }) {
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
) : (
|
||||
<div className="h-full w-full bg-black" />
|
||||
) : null}
|
||||
<MediaSizeChip att={att} />
|
||||
{isVideo ? (
|
||||
<div className="absolute inset-0 grid place-items-center">
|
||||
<span className="grid h-16 w-16 place-items-center rounded-full bg-black/55 text-white backdrop-blur-sm">
|
||||
<Play className="ml-1 h-8 w-8 fill-current" />
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
{showExtra ? (
|
||||
<div className="absolute inset-0 grid place-items-center bg-black/55 text-[24px] font-bold text-white backdrop-blur-sm">
|
||||
+{showExtra}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function MediaGrid({ attachments }: { attachments: Attachment[] }) {
|
||||
const visible = attachments.slice(0, 4);
|
||||
const extra = Math.max(0, attachments.length - visible.length);
|
||||
if (visible.length === 0) return <div className="h-full w-full bg-black" />;
|
||||
if (visible.length === 1) return <MediaTile att={visible[0]} />;
|
||||
if (visible.length === 2) {
|
||||
return (
|
||||
<div className="grid h-full w-full grid-cols-2 gap-0">
|
||||
{visible.map((att) => (
|
||||
<MediaTile key={att.id} att={att} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (visible.length === 3) {
|
||||
return (
|
||||
<div className="grid h-full w-full grid-cols-2 gap-0">
|
||||
<MediaTile att={visible[0]} />
|
||||
<div className="grid h-full grid-rows-2 gap-0">
|
||||
<MediaTile att={visible[1]} />
|
||||
<MediaTile att={visible[2]} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="grid h-full w-full grid-cols-2 grid-rows-2 gap-0">
|
||||
{visible.map((att, index) => (
|
||||
<div key={att.id} className="relative overflow-hidden bg-black">
|
||||
<img
|
||||
src={attachmentPreview(att)}
|
||||
alt=""
|
||||
className="h-full w-full object-cover"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
<MediaTile
|
||||
key={att.id}
|
||||
att={att}
|
||||
showExtra={extra > 0 && index === visible.length - 1 ? extra : 0}
|
||||
/>
|
||||
{extra > 0 && index === visible.length - 1 ? (
|
||||
<div className="absolute inset-0 grid place-items-center bg-black/55 text-[24px] font-bold text-white backdrop-blur-sm">
|
||||
+{extra}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function MediaBadge({ att }: { att?: Attachment }) {
|
||||
if (!att) return null;
|
||||
return (
|
||||
<div className="absolute left-3 top-3 z-20 inline-flex h-8 items-center overflow-hidden rounded-full bg-black/75 text-[12px] font-medium text-white shadow-lg backdrop-blur">
|
||||
<span className="grid h-8 w-8 place-items-center rounded-full bg-[#3a3a40]">
|
||||
<DownloadCloudIcon />
|
||||
</span>
|
||||
<span className="px-3">{formatBytes(att.sizeBytes)}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function VisualCard({ post }: { post: Post }) {
|
||||
const { lang } = useI18n();
|
||||
const att = post.attachments[0];
|
||||
@@ -213,21 +268,13 @@ function VisualCard({ post }: { post: Post }) {
|
||||
}`}
|
||||
>
|
||||
<MediaGrid attachments={post.attachments} />
|
||||
<MediaBadge att={att} />
|
||||
{isVideo ? (
|
||||
<div className="absolute inset-0 grid place-items-center">
|
||||
<span className="grid h-14 w-14 place-items-center rounded-full bg-black/55 text-white backdrop-blur-sm">
|
||||
<Play className="ml-1 h-7 w-7 fill-current" />
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{text || post.title ? (
|
||||
<div className="message-stream-copyable-text whitespace-pre-wrap break-words px-4 pt-3 text-[15px] font-medium leading-6 text-white">
|
||||
{autolink(text || post.title || "")}
|
||||
</div>
|
||||
) : null}
|
||||
<Footer post={post} attachment={att} />
|
||||
<Footer post={post} />
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user