MediaAttachmentGrid: correct but slow layout
All checks were successful
/ depoly (push) Successful in 1m26s

This commit is contained in:
thislight 2024-10-28 18:26:59 +08:00
parent 7bb6c0b826
commit 726abbe893
No known key found for this signature in database
GPG key ID: A50F9451AC56A63E
2 changed files with 73 additions and 20 deletions

View file

@ -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}
/>
);

View file

@ -223,6 +223,7 @@
}
.tootAttachmentGrp {
/* Note: MeidaAttachmentGrid has hard-coded layout calcalation */
composes: cardNoPad from "../material/cards.module.css";
margin-top: 1em;
margin-left: calc(var(--card-pad, 0) + var(--toot-avatar-size, 0) + 8px);
@ -233,14 +234,12 @@
max-height: 35vh;
min-height: 40px;
min-width: 40px;
width: auto;
height: auto;
object-fit: contain;
max-width: 100%;
background-color: var(--tutu-color-surface-d);
border-radius: 2px;
border: 1px solid var(--tutu-color-on-surface-d);
transition: outline-width 60ms var(--tutu-anim-curve-std), z-index 60ms var(--tutu-anim-curve-std);
border: 1px solid var(--tutu-color-surface-d);
transition: outline-width 60ms var(--tutu-anim-curve-std), border-color 60ms var(--tutu-anim-curve-std);
&:hover,
&:focus-visible {
@ -248,6 +247,7 @@
/* but our infra is not prepared for this. The average color thing is slow */
/* and we need further managing to control its performance impact. */
outline: 8px solid var(--media-color-accent, var(--tutu-color-surface-d));
border-color: transparent;
}
}
}