tutu/src/timelines/MediaAttachmentGrid.tsx
2024-07-14 20:28:44 +08:00

80 lines
2.2 KiB
TypeScript

import type { mastodon } from "masto";
import { type Component, For, createSignal } from "solid-js";
import { css } from "solid-styled";
import tootStyle from "./toot.module.css";
import { Portal } from "solid-js/web";
import MediaViewer, { MEDIA_VIEWER_HEROSRC } from "./MediaViewer";
import { HeroSourceProvider } from "../platform/anim";
const MediaAttachmentGrid: Component<{
attachments: mastodon.v1.MediaAttachment[];
}> = (props) => {
let rootRef: HTMLElement;
const [viewerIndex, setViewerIndex] = createSignal<number>();
const viewerOpened = () => typeof viewerIndex() !== "undefined"
const gridTemplateColumns = () => {
const l = props.attachments.length;
if (l < 2) {
return "1fr";
}
if (l < 4) {
return "repeat(2, 1fr)";
}
return "repeat(3, 1fr)";
};
const openViewerFor = (index: number) => {
setViewerIndex(index);
};
css`
.attachments {
grid-template-columns: ${gridTemplateColumns()};
}
`;
return (
<section
ref={rootRef!}
class={[tootStyle.tootAttachmentGrp, "attachments"].join(" ")}
onClick={(e) => e.stopImmediatePropagation()}
>
<For each={props.attachments}>
{(item, index) => {
switch (item.type) {
case "image":
return (
<img
src={item.previewUrl}
alt={item.description || undefined}
onClick={[openViewerFor, index()]}
loading="lazy"
></img>
);
case "video":
case "gifv":
case "audio":
case "unknown":
return <div></div>;
}
}}
</For>
<HeroSourceProvider
value={() => ({
[MEDIA_VIEWER_HEROSRC]: rootRef.children.item(
viewerIndex() || 0,
) as HTMLElement,
})}
>
<MediaViewer
show={viewerOpened()}
index={viewerIndex() || 0}
onIndexUpdated={setViewerIndex}
media={props.attachments}
onClose={() => setViewerIndex(undefined)}
/>
</HeroSourceProvider>
</section>
);
};
export default MediaAttachmentGrid;