Fix attachment scaling.

This commit is contained in:
Paul 2021-07-10 15:21:35 +01:00
parent 92fed40e40
commit 9846262e8b
9 changed files with 164 additions and 111 deletions

View file

@ -57,6 +57,7 @@ export default function ChannelIcon(
{...imgProps} {...imgProps}
width={size} width={size}
height={size} height={size}
loading="lazy"
aria-hidden="true" aria-hidden="true"
square={isServerChannel} square={isServerChannel}
src={iconURL ?? fallback} src={iconURL ?? fallback}

View file

@ -61,8 +61,9 @@ export default function ServerIcon(
{...imgProps} {...imgProps}
width={size} width={size}
height={size} height={size}
aria-hidden="true"
src={iconURL} src={iconURL}
loading="lazy"
aria-hidden="true"
/> />
); );
} }

View file

@ -3,67 +3,15 @@
grid-auto-columns: min(100%, 480px); grid-auto-columns: min(100%, 480px);
grid-auto-flow: row dense; grid-auto-flow: row dense;
margin: .125rem 0 .125rem;
width: max-content; width: max-content;
max-width: 100%; max-width: 100%;
border-radius: 6px;
margin: .125rem 0 .125rem;
&[data-spoiler="true"] { &[data-spoiler="true"] {
filter: blur(30px); filter: blur(30px);
pointer-events: none; pointer-events: none;
} }
&[data-has-content="true"] {
margin-top: 4px;
}
&.image, &.video > video {
cursor: pointer;
aspect-ratio: var(--width) / var(--height);
max-height: min(640px, var(--height-px));
max-width: min(480px, 100%, var(--width-px));
object-fit: contain;
object-position: top left;
}
&.image {
&.long {
width: min(100%, var(--width-px));
height: auto;
}
&.tall {
height: min(100%, var(--height-px));
width: 100%;
&.loaded {
width: auto;
}
}
}
&.video {
.actions {
padding: 10px 12px;
border-radius: 6px 6px 0 0;
}
video {
border-radius: 0 0 6px 6px;
&.long {
height: auto;
}
&.tall {
width: auto;
}
}
}
&.audio { &.audio {
gap: 4px; gap: 4px;
padding: 6px; padding: 6px;
@ -125,52 +73,20 @@
} }
} }
.actions.imageAction { .margin {
grid-template: margin-top: 4px;
"name icon external download" auto
"size icon external download" auto
/ minmax(20px, 1fr) min-content min-content;
} }
.actions { .container {
display: grid; max-width: 100%;
grid-template:
"icon name external download" auto
"icon size external download" auto
/ min-content minmax(20px, 1fr) min-content;
align-items: center;
column-gap: 12px;
width: 100%;
padding: 8px;
overflow: none;
color: var(--foreground);
background: var(--secondary-background);
span {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden; overflow: hidden;
width: fit-content;
> :first-child {
width: min(480px, 100%, var(--width));
}
} }
.filesize { .container, .attachment, .image {
grid-area: size; border-radius: 6px;
font-size: 10px;
color: var(--secondary-foreground);
}
.downloadIcon {
grid-area: download;
}
.externalType {
grid-area: external;
}
.iconType {
grid-area: icon;
}
} }

View file

@ -8,9 +8,9 @@ import { useContext, useState } from "preact/hooks";
import { useIntermediate } from "../../../../context/intermediate/Intermediate"; import { useIntermediate } from "../../../../context/intermediate/Intermediate";
import { AppContext } from "../../../../context/revoltjs/RevoltClient"; import { AppContext } from "../../../../context/revoltjs/RevoltClient";
import { MessageAreaWidthContext } from "../../../../pages/channels/messaging/MessageArea";
import AttachmentActions from "./AttachmentActions"; import AttachmentActions from "./AttachmentActions";
import TextFile from "./TextFile"; import TextFile from "./TextFile";
import { SizedGrid } from "./Grid";
interface Props { interface Props {
attachment: AttachmentRJS; attachment: AttachmentRJS;
@ -35,6 +35,44 @@ export default function Attachment({ attachment, hasContent }: Props) {
switch (metadata.type) { switch (metadata.type) {
case "Image": { case "Image": {
return ( return (
<SizedGrid width={metadata.width} height={metadata.height}
className={classNames({ [styles.margin]: hasContent })}>
<img src={url} alt={filename}
className={styles.image}
loading="lazy"
onClick={() =>
openScreen({ id: "image_viewer", attachment })
}
onMouseDown={(ev) =>
ev.button === 1 && window.open(url, "_blank")
} />
</SizedGrid>
)
}
case "Video": {
return (
<div className={classNames(styles.container, { [styles.margin]: hasContent })}
style={{ '--width': metadata.width + 'px' }}>
<AttachmentActions attachment={attachment} />
<SizedGrid width={metadata.width} height={metadata.height}>
<video src={url} alt={filename}
controls
loading="lazy"
width={metadata.width}
height={metadata.height}
onMouseDown={(ev) =>
ev.button === 1 && window.open(url, "_blank")
}
/>
</SizedGrid>
</div>
)
}
/*return (
<div <div
className={styles.container} className={styles.container}
onClick={() => spoiler && setSpoiler(false)}> onClick={() => spoiler && setSpoiler(false)}>
@ -51,8 +89,8 @@ export default function Attachment({ attachment, hasContent }: Props) {
width={metadata.width} width={metadata.width}
height={metadata.height} height={metadata.height}
loading="lazy" loading="lazy"
data-spoiler={spoiler}
data-has-content={hasContent} data-has-content={hasContent}
data-spoiler={spoiler}
className={classNames( className={classNames(
styles.attachment, styles.attachment,
styles.image, styles.image,
@ -70,14 +108,14 @@ export default function Attachment({ attachment, hasContent }: Props) {
onClick={() => onClick={() =>
openScreen({ id: "image_viewer", attachment }) openScreen({ id: "image_viewer", attachment })
} }
onLoad={() => setLoaded(true)}
onMouseDown={(ev) => onMouseDown={(ev) =>
ev.button === 1 && window.open(url, "_blank") ev.button === 1 && window.open(url, "_blank")
} }
onLoad={() => setLoaded(true)}
/> />
</div> </div>
); );
} }*/
case "Audio": { case "Audio": {
return ( return (
<div <div
@ -88,7 +126,7 @@ export default function Attachment({ attachment, hasContent }: Props) {
</div> </div>
); );
} }
case "Video": { /*case "Video": {
return ( return (
<div <div
className={styles.container} className={styles.container}
@ -129,7 +167,7 @@ export default function Attachment({ attachment, hasContent }: Props) {
</div> </div>
</div> </div>
); );
} }*/
case "Text": { case "Text": {
return ( return (
<div <div

View file

@ -0,0 +1,49 @@
.actions.imageAction {
grid-template:
"name icon external download" auto
"size icon external download" auto
/ minmax(20px, 1fr) min-content min-content;
}
.actions {
display: grid;
grid-template:
"icon name external download" auto
"icon size external download" auto
/ min-content minmax(20px, 1fr) min-content;
align-items: center;
column-gap: 12px;
width: 100%;
padding: 8px;
overflow: none;
color: var(--foreground);
background: var(--secondary-background);
span {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.filesize {
grid-area: size;
font-size: 10px;
color: var(--secondary-foreground);
}
.downloadIcon {
grid-area: download;
}
.externalType {
grid-area: external;
}
.iconType {
grid-area: icon;
}
}

View file

@ -7,7 +7,7 @@ import {
} from "@styled-icons/boxicons-regular"; } from "@styled-icons/boxicons-regular";
import { Attachment } from "revolt.js/dist/api/objects"; import { Attachment } from "revolt.js/dist/api/objects";
import styles from "./Attachment.module.scss"; import styles from "./AttachmentActions.module.scss";
import classNames from "classnames"; import classNames from "classnames";
import { useContext } from "preact/hooks"; import { useContext } from "preact/hooks";

View file

@ -0,0 +1,47 @@
import styled from "styled-components";
import { Children } from "../../../../types/Preact";
const Grid = styled.div`
display: grid;
max-width: min(480px, 100%, var(--width));
max-height: min(640px, var(--height));
aspect-ratio: var(--aspect-ratio);
img, video {
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
grid-area: 1 / 1;
}
`;
export default Grid;
type Props = Omit<JSX.HTMLAttributes<HTMLDivElement>, 'children' | 'as' | 'style'> & {
style?: JSX.CSSProperties,
children?: Children,
width: number,
height: number,
};
export function SizedGrid(props: Props) {
const { width, height, children, style, ...divProps } = props;
return (
<Grid {...divProps}
style={{
...style,
"--width": width + 'px',
"--height": height + 'px',
"--aspect-ratio": width / height,
}}>
{ children }
</Grid>
)
}

View file

@ -87,7 +87,7 @@ export default function UserIcon(
width="32" width="32"
height="32" height="32"
mask={mask ?? (status ? "url(#user)" : undefined)}> mask={mask ?? (status ? "url(#user)" : undefined)}>
{<img src={iconURL} draggable={false} />} {<img src={iconURL} draggable={false} loading="lazy" />}
</foreignObject> </foreignObject>
{props.status && ( {props.status && (
<circle cx="27" cy="27" r="5" fill={useStatusColour(target)} /> <circle cx="27" cy="27" r="5" fill={useStatusColour(target)} />

View file

@ -132,7 +132,8 @@ const ServerEntry = styled.div<{ active: boolean; home?: boolean }>`
` } ` }
svg { svg {
width: 56.5px; width: 57px;
height: 117px;
margin-top: 4px; margin-top: 4px;
display: relative; display: relative;
@ -151,10 +152,10 @@ const ServerEntry = styled.div<{ active: boolean; home?: boolean }>`
function Swoosh() { function Swoosh() {
return ( return (
<span> <span>
<svg width="56" height="118" viewBox="0 0 56 118" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg xmlns="http://www.w3.org/2000/svg" width="57" height="117" fill="var(--sidebar-active)">
<path d="M55.9957 0C55.6241 18.5052 31.292 28.1152 19.2904 32.1029L56 68.8124L55.9957 0Z" fill="var(--sidebar-active)"/> <path d="M27.746 86.465c14 0 28 11.407 28 28s.256-56 .256-56-42.256 28-28.256 28z"/>
<path d="M55.9963 117.633C55.8689 98.6899 31.3298 87.9423 19.2144 84.8847L55.9968 47.5654L55.9963 117.633Z" fill="var(--sidebar-active)"/> <path d="M56 58.465c0 15.464-12.536 28-28 28s-28-12.536-28-28 12.536-28 28-28 28 12.536 28 28z"/>
<path d="M55.5682 58.4474C55.5682 73.7921 43.1288 86.2315 27.7841 86.2315C12.4394 86.2315 0 73.7921 0 58.4474C0 43.1026 12.4394 30.6633 27.7841 30.6633C43.1288 30.6633 55.5682 43.1026 55.5682 58.4474Z" fill="var(--sidebar-active)"/> <path d="M28.002 30.465c14 0 28-11.407 28-28s0 56 0 56-42-28-28-28z"/>
</svg> </svg>
</span> </span>
) )