MediaAttachmentGrid: correct but slow layout
All checks were successful
/ depoly (push) Successful in 1m26s
All checks were successful
/ depoly (push) Successful in 1m26s
This commit is contained in:
parent
7bb6c0b826
commit
726abbe893
2 changed files with 73 additions and 20 deletions
|
@ -2,29 +2,52 @@ import type { mastodon } from "masto";
|
|||
import {
|
||||
type Component,
|
||||
For,
|
||||
createEffect,
|
||||
createMemo,
|
||||
createRenderEffect,
|
||||
createSignal,
|
||||
onCleanup,
|
||||
onMount,
|
||||
} from "solid-js";
|
||||
import { css } from "solid-styled";
|
||||
import tootStyle from "./toot.module.css";
|
||||
import MediaViewer from "./MediaViewer";
|
||||
import { render } from "solid-js/web";
|
||||
import { useWindowSize } from "@solid-primitives/resize-observer";
|
||||
import {
|
||||
createElementSize,
|
||||
useWindowSize,
|
||||
} from "@solid-primitives/resize-observer";
|
||||
import { useStore } from "@nanostores/solid";
|
||||
import { $settings } from "../settings/stores";
|
||||
|
||||
type ElementSize = { width: number; height: number };
|
||||
|
||||
function constraintedSize(
|
||||
{ width: owidth, height: oheight }: Readonly<ElementSize>, // originalSize
|
||||
{ width: mwidth, height: mheight }: Readonly<Partial<ElementSize>>, // modifier
|
||||
{ width: maxWidth, height: maxHeight }: Readonly<ElementSize>, // maxSize
|
||||
) {
|
||||
const ySize = owidth + (mwidth ?? 0);
|
||||
const yScale = ySize > maxWidth ? ySize / maxWidth : 1;
|
||||
const xSize = oheight + (mheight ?? 0);
|
||||
const xScale = xSize > maxHeight ? xSize / maxHeight : 1;
|
||||
|
||||
const maxScale = Math.max(yScale, xScale);
|
||||
const scaledWidth = owidth / maxScale;
|
||||
const scaledHeight = oheight / maxScale;
|
||||
|
||||
return {
|
||||
width: scaledWidth,
|
||||
height: scaledHeight,
|
||||
};
|
||||
}
|
||||
|
||||
const MediaAttachmentGrid: Component<{
|
||||
attachments: mastodon.v1.MediaAttachment[];
|
||||
}> = (props) => {
|
||||
let rootRef: HTMLElement;
|
||||
const [rootRef, setRootRef] = createSignal<HTMLElement>();
|
||||
const [viewerIndex, setViewerIndex] = createSignal<number>();
|
||||
const viewerOpened = () => typeof viewerIndex() !== "undefined";
|
||||
const windowSize = useWindowSize();
|
||||
const vh35 = () => Math.floor(windowSize.height * 0.35);
|
||||
const settings = useStore($settings);
|
||||
const windowSize = useWindowSize();
|
||||
|
||||
createRenderEffect((lastDispose?: () => void) => {
|
||||
lastDispose?.();
|
||||
|
@ -64,6 +87,22 @@ const MediaAttachmentGrid: Component<{
|
|||
}
|
||||
};
|
||||
|
||||
const rawElementSize = createElementSize(rootRef);
|
||||
|
||||
const elementWidth = () => rawElementSize.width;
|
||||
|
||||
const itemMaxSize = createMemo(() => {
|
||||
const ewidth = elementWidth();
|
||||
const width = ewidth
|
||||
? (ewidth - (columnCount() - 1) * 4) / columnCount()
|
||||
: 1;
|
||||
|
||||
return {
|
||||
height: windowSize.height * 0.35,
|
||||
width,
|
||||
};
|
||||
});
|
||||
|
||||
css`
|
||||
.attachments {
|
||||
column-count: ${columnCount().toString()};
|
||||
|
@ -71,7 +110,7 @@ const MediaAttachmentGrid: Component<{
|
|||
`;
|
||||
return (
|
||||
<section
|
||||
ref={rootRef!}
|
||||
ref={setRootRef}
|
||||
class={[tootStyle.tootAttachmentGrp, "attachments"].join(" ")}
|
||||
onClick={(e) => {
|
||||
if (e.target !== e.currentTarget) {
|
||||
|
@ -89,19 +128,33 @@ const MediaAttachmentGrid: Component<{
|
|||
// before using this. See #37.
|
||||
// TODO: use fast average color to extract accent color
|
||||
const accentColor = item.meta?.colors?.accent;
|
||||
const { width, height } = item.meta?.small || {};
|
||||
|
||||
const size = () => {
|
||||
return constraintedSize(
|
||||
item.meta?.small || { width: 1, height: 1 },
|
||||
{ width: 2, height: 2 },
|
||||
itemMaxSize(),
|
||||
);
|
||||
};
|
||||
|
||||
switch (item.type) {
|
||||
case "image":
|
||||
return (
|
||||
<img
|
||||
src={item.previewUrl}
|
||||
width={item.meta?.small?.width}
|
||||
height={item.meta?.small?.height}
|
||||
width={width}
|
||||
height={height}
|
||||
alt={item.description || undefined}
|
||||
onClick={[openViewerFor, index()]}
|
||||
loading="lazy"
|
||||
style={
|
||||
accentColor ? { "--media-color-accent": accentColor } : {}
|
||||
}
|
||||
style={Object.assign(
|
||||
{
|
||||
width: `${size().width}px`,
|
||||
height: `${size().height}px`,
|
||||
},
|
||||
accentColor ? { "--media-color-accent": accentColor } : {},
|
||||
)}
|
||||
></img>
|
||||
);
|
||||
case "video":
|
||||
|
@ -112,8 +165,8 @@ const MediaAttachmentGrid: Component<{
|
|||
playsinline={settings().autoPlayVideos ? true : undefined}
|
||||
controls
|
||||
poster={item.previewUrl}
|
||||
width={item.meta?.small?.width}
|
||||
height={item.meta?.small?.height}
|
||||
width={width}
|
||||
height={height}
|
||||
/>
|
||||
);
|
||||
case "gifv":
|
||||
|
@ -125,8 +178,8 @@ const MediaAttachmentGrid: Component<{
|
|||
playsinline /* or safari on iOS will play in full-screen */
|
||||
loop
|
||||
poster={item.previewUrl}
|
||||
width={item.meta?.small?.width}
|
||||
height={item.meta?.small?.height}
|
||||
width={width}
|
||||
height={height}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue