MediaAttachmentGrid: major layout revised
* Now the media preview use masonry layout * Supports preview video media
This commit is contained in:
parent
1a0a9d7e77
commit
de03e62783
2 changed files with 28 additions and 14 deletions
|
@ -12,24 +12,16 @@ import { css } from "solid-styled";
|
||||||
import tootStyle from "./toot.module.css";
|
import tootStyle from "./toot.module.css";
|
||||||
import MediaViewer from "./MediaViewer";
|
import MediaViewer from "./MediaViewer";
|
||||||
import { render } from "solid-js/web";
|
import { render } from "solid-js/web";
|
||||||
|
import { useWindowSize } from "@solid-primitives/resize-observer";
|
||||||
|
|
||||||
const MediaAttachmentGrid: Component<{
|
const MediaAttachmentGrid: Component<{
|
||||||
attachments: mastodon.v1.MediaAttachment[];
|
attachments: mastodon.v1.MediaAttachment[];
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
let rootRef: HTMLElement;
|
let rootRef: HTMLElement;
|
||||||
const [dispose, setDispose] = createSignal<() => void>();
|
|
||||||
const [viewerIndex, setViewerIndex] = createSignal<number>();
|
const [viewerIndex, setViewerIndex] = createSignal<number>();
|
||||||
const viewerOpened = () => typeof viewerIndex() !== "undefined";
|
const viewerOpened = () => typeof viewerIndex() !== "undefined";
|
||||||
const gridTemplateColumns = () => {
|
const windowSize = useWindowSize();
|
||||||
const l = props.attachments.length;
|
const vh35 = () => Math.floor(windowSize.height * 0.35);
|
||||||
if (l < 2) {
|
|
||||||
return "minmax(40px, auto)";
|
|
||||||
}
|
|
||||||
if (l < 4) {
|
|
||||||
return "repeat(2, minmax(40px, auto))";
|
|
||||||
}
|
|
||||||
return "repeat(3, minmax(40px, auto))";
|
|
||||||
};
|
|
||||||
|
|
||||||
createRenderEffect((lastDispose?: () => void) => {
|
createRenderEffect((lastDispose?: () => void) => {
|
||||||
lastDispose?.();
|
lastDispose?.();
|
||||||
|
@ -61,7 +53,7 @@ const MediaAttachmentGrid: Component<{
|
||||||
|
|
||||||
css`
|
css`
|
||||||
.attachments {
|
.attachments {
|
||||||
grid-template-columns: ${gridTemplateColumns()};
|
column-count: ${(props.attachments.length === 1 ? 1 : 3).toString()};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
return (
|
return (
|
||||||
|
@ -72,17 +64,39 @@ const MediaAttachmentGrid: Component<{
|
||||||
>
|
>
|
||||||
<For each={props.attachments}>
|
<For each={props.attachments}>
|
||||||
{(item, index) => {
|
{(item, index) => {
|
||||||
|
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(),
|
||||||
|
};
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case "image":
|
case "image":
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
src={item.previewUrl}
|
src={item.previewUrl}
|
||||||
|
style={style}
|
||||||
alt={item.description || undefined}
|
alt={item.description || undefined}
|
||||||
onClick={[openViewerFor, index()]}
|
onClick={[openViewerFor, index()]}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
></img>
|
></img>
|
||||||
);
|
);
|
||||||
case "video":
|
case "video":
|
||||||
|
return (
|
||||||
|
<video
|
||||||
|
src={item.url || undefined}
|
||||||
|
style={style}
|
||||||
|
autoplay={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
case "gifv":
|
case "gifv":
|
||||||
case "audio":
|
case "audio":
|
||||||
case "unknown":
|
case "unknown":
|
||||||
|
|
|
@ -222,12 +222,12 @@
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
margin-left: calc(var(--card-pad, 0) + var(--toot-avatar-size, 0) + 8px);
|
margin-left: calc(var(--card-pad, 0) + var(--toot-avatar-size, 0) + 8px);
|
||||||
margin-right: var(--card-pad, 0);
|
margin-right: var(--card-pad, 0);
|
||||||
display: grid;
|
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
|
||||||
> :where(img) {
|
> :where(img, video) {
|
||||||
max-height: 35vh;
|
max-height: 35vh;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
|
min-width: 40px;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
background-color: var(--tutu-color-surface-d);
|
background-color: var(--tutu-color-surface-d);
|
||||||
|
|
Loading…
Reference in a new issue