2024-07-14 12:28:44 +00:00
|
|
|
import type { mastodon } from "masto";
|
2024-09-14 12:43:44 +00:00
|
|
|
import {
|
|
|
|
type Component,
|
|
|
|
For,
|
2024-09-14 13:17:03 +00:00
|
|
|
createEffect,
|
|
|
|
createRenderEffect,
|
2024-09-14 12:43:44 +00:00
|
|
|
createSignal,
|
|
|
|
onCleanup,
|
|
|
|
onMount,
|
|
|
|
} from "solid-js";
|
2024-07-14 12:28:44 +00:00
|
|
|
import { css } from "solid-styled";
|
|
|
|
import tootStyle from "./toot.module.css";
|
2024-08-12 13:55:26 +00:00
|
|
|
import MediaViewer from "./MediaViewer";
|
2024-09-14 12:21:19 +00:00
|
|
|
import { render } from "solid-js/web";
|
2024-09-23 07:43:49 +00:00
|
|
|
import { useWindowSize } from "@solid-primitives/resize-observer";
|
2024-07-14 12:28:44 +00:00
|
|
|
|
|
|
|
const MediaAttachmentGrid: Component<{
|
|
|
|
attachments: mastodon.v1.MediaAttachment[];
|
|
|
|
}> = (props) => {
|
|
|
|
let rootRef: HTMLElement;
|
|
|
|
const [viewerIndex, setViewerIndex] = createSignal<number>();
|
2024-08-05 07:33:00 +00:00
|
|
|
const viewerOpened = () => typeof viewerIndex() !== "undefined";
|
2024-09-23 07:43:49 +00:00
|
|
|
const windowSize = useWindowSize();
|
|
|
|
const vh35 = () => Math.floor(windowSize.height * 0.35);
|
2024-07-14 12:28:44 +00:00
|
|
|
|
2024-09-14 13:17:03 +00:00
|
|
|
createRenderEffect((lastDispose?: () => void) => {
|
|
|
|
lastDispose?.();
|
|
|
|
const vidx = viewerIndex();
|
|
|
|
if (typeof vidx === "undefined") return;
|
2024-09-14 12:21:19 +00:00
|
|
|
const container = document.createElement("div");
|
|
|
|
container.setAttribute("role", "presentation");
|
|
|
|
document.body.appendChild(container);
|
2024-09-14 13:17:03 +00:00
|
|
|
return render(() => {
|
|
|
|
onCleanup(() => {
|
|
|
|
document.body.removeChild(container);
|
|
|
|
});
|
2024-09-14 12:43:44 +00:00
|
|
|
|
2024-09-14 12:21:19 +00:00
|
|
|
return (
|
|
|
|
<MediaViewer
|
|
|
|
show={viewerOpened()}
|
|
|
|
index={viewerIndex() || 0}
|
|
|
|
onIndexUpdated={setViewerIndex}
|
|
|
|
media={props.attachments}
|
2024-09-14 13:17:03 +00:00
|
|
|
onClose={() => setViewerIndex()}
|
2024-09-14 12:21:19 +00:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
}, container);
|
2024-09-14 13:17:03 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
const openViewerFor = (index: number) => {
|
|
|
|
setViewerIndex(index);
|
2024-07-14 12:28:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
css`
|
|
|
|
.attachments {
|
2024-09-23 07:43:49 +00:00
|
|
|
column-count: ${(props.attachments.length === 1 ? 1 : 3).toString()};
|
2024-07-14 12:28:44 +00:00
|
|
|
}
|
|
|
|
`;
|
|
|
|
return (
|
|
|
|
<section
|
|
|
|
ref={rootRef!}
|
|
|
|
class={[tootStyle.tootAttachmentGrp, "attachments"].join(" ")}
|
|
|
|
onClick={(e) => e.stopImmediatePropagation()}
|
|
|
|
>
|
|
|
|
<For each={props.attachments}>
|
|
|
|
{(item, index) => {
|
2024-09-23 07:43:49 +00:00
|
|
|
const width = item.meta?.small?.width;
|
|
|
|
const height = item.meta?.small?.height;
|
|
|
|
const aspectRatio = item.meta?.small?.aspect;
|
|
|
|
const maxHeight = vh35();
|
|
|
|
const realHeight = height && height > maxHeight ? maxHeight : height;
|
|
|
|
const realWidth =
|
|
|
|
height && height > maxHeight
|
|
|
|
? maxHeight * (aspectRatio ?? 1)
|
|
|
|
: width;
|
|
|
|
const style = {
|
|
|
|
width: realWidth ? `${realWidth}px` : undefined,
|
|
|
|
height: realHeight ? `${realHeight}px` : undefined,
|
|
|
|
"aspect-ratio": aspectRatio?.toString(),
|
|
|
|
};
|
2024-07-14 12:28:44 +00:00
|
|
|
switch (item.type) {
|
|
|
|
case "image":
|
|
|
|
return (
|
|
|
|
<img
|
|
|
|
src={item.previewUrl}
|
2024-09-23 07:43:49 +00:00
|
|
|
style={style}
|
2024-07-14 12:28:44 +00:00
|
|
|
alt={item.description || undefined}
|
|
|
|
onClick={[openViewerFor, index()]}
|
|
|
|
loading="lazy"
|
|
|
|
></img>
|
|
|
|
);
|
|
|
|
case "video":
|
2024-09-23 07:43:49 +00:00
|
|
|
return (
|
|
|
|
<video
|
|
|
|
src={item.url || undefined}
|
|
|
|
style={style}
|
|
|
|
autoplay={false}
|
|
|
|
/>
|
|
|
|
);
|
2024-07-14 12:28:44 +00:00
|
|
|
case "gifv":
|
|
|
|
case "audio":
|
|
|
|
case "unknown":
|
|
|
|
return <div></div>;
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
</For>
|
|
|
|
</section>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default MediaAttachmentGrid;
|