Fix: attachment scaling and better image scaling

- attachment scaling now works for all forms of attachments
- switched to grid based action bar
- added onLoad class so image proportions are "trimmed" once the image has loaded to avoid moving the view around before loading
  - this may be possible to remove at some point
This commit is contained in:
bree 2021-07-05 04:32:05 -04:00
parent b19479f1b1
commit 02bbf78dcd
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG key ID: 1B2E56B9EC985B96
3 changed files with 89 additions and 60 deletions

View file

@ -1,14 +1,13 @@
.attachment { .attachment {
display: grid;
grid-auto-columns: min(100%, 480px);
grid-auto-flow: row dense;
width: max-content;
border-radius: 6px; border-radius: 6px;
margin: .125rem 0 .125rem; margin: .125rem 0 .125rem;
height: auto;
max-height: 640px;
max-width: min(480px, 100%);
object-fit: contain;
&[data-spoiler="true"] { &[data-spoiler="true"] {
filter: blur(30px); filter: blur(30px);
pointer-events: none; pointer-events: none;
@ -20,6 +19,16 @@
&.image { &.image {
cursor: pointer; cursor: pointer;
max-height: 640px;
max-width: min(480px, 100%);
object-fit: contain;
&.loaded {
width: auto;
height: auto;
}
} }
&.video { &.video {
@ -29,8 +38,15 @@
} }
video { video {
width: 100%;
border-radius: 0 0 6px 6px; border-radius: 0 0 6px 6px;
max-height: 640px;
max-width: min(480px, 100%);
}
video.loaded {
width: auto;
height: auto;
} }
} }
@ -59,11 +75,12 @@
} }
&.text { &.text {
display: flex; width: 100%;
overflow: hidden;
max-width: 800px; max-width: 800px;
overflow: hidden;
grid-auto-columns: unset;
border-radius: 6px; border-radius: 6px;
flex-direction: column;
.textContent { .textContent {
height: 140px; height: 140px;
@ -92,35 +109,48 @@
} }
} }
.actions.imageAction {
grid-template:
"name icon download" auto
"size icon download" auto
/ minmax(20px, 1fr) min-content min-content;
}
.actions { .actions {
gap: 8px; display: grid;
padding: 8px; grid-template:
display: flex; "icon name download" auto
overflow: none; "icon size download" auto
max-width: 100%; / min-content minmax(20px, 1fr) min-content;
align-items: center; align-items: center;
flex-direction: row; column-gap: 8px;
width: 100%;
padding: 8px;
overflow: none;
color: var(--foreground); color: var(--foreground);
background: var(--secondary-background); background: var(--secondary-background);
> svg { span {
flex-shrink: 0;
}
.info {
display: flex;
flex-direction: column;
flex-grow: 1;
> span {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
} }
.filesize { .filesize {
grid-area: size;
font-size: 10px; font-size: 10px;
color: var(--secondary-foreground); color: var(--secondary-foreground);
} }
.downloadIcon {
grid-area: download;
}
.iconType {
grid-area: icon;
} }
} }

View file

@ -21,6 +21,7 @@ export default function Attachment({ attachment, hasContent }: Props) {
const { openScreen } = useIntermediate(); const { openScreen } = useIntermediate();
const { filename, metadata } = attachment; const { filename, metadata } = attachment;
const [ spoiler, setSpoiler ] = useState(filename.startsWith("SPOILER_")); const [ spoiler, setSpoiler ] = useState(filename.startsWith("SPOILER_"));
const [ loaded, setLoaded ] = useState(false)
const url = client.generateFileURL(attachment, { width: MAX_ATTACHMENT_WIDTH * 1.5 }, true); const url = client.generateFileURL(attachment, { width: MAX_ATTACHMENT_WIDTH * 1.5 }, true);
@ -44,7 +45,7 @@ export default function Attachment({ attachment, hasContent }: Props) {
height={metadata.height} height={metadata.height}
data-spoiler={spoiler} data-spoiler={spoiler}
data-has-content={hasContent} data-has-content={hasContent}
className={classNames(styles.attachment, styles.image)} className={classNames(styles.attachment, styles.image, loaded && styles.loaded)}
onClick={() => onClick={() =>
openScreen({ id: "image_viewer", attachment }) openScreen({ id: "image_viewer", attachment })
} }
@ -52,6 +53,7 @@ export default function Attachment({ attachment, hasContent }: Props) {
ev.button === 1 && ev.button === 1 &&
window.open(url, "_blank") window.open(url, "_blank")
} }
onLoad={() => setLoaded(true)}
/> />
</div> </div>
); );
@ -85,11 +87,15 @@ export default function Attachment({ attachment, hasContent }: Props) {
<AttachmentActions attachment={attachment} /> <AttachmentActions attachment={attachment} />
<video <video
src={url} src={url}
width={metadata.width}
height={metadata.height}
className={classNames(loaded && styles.loaded)}
controls controls
onMouseDown={ev => onMouseDown={ev =>
ev.button === 1 && ev.button === 1 &&
window.open(url, "_blank") window.open(url, "_blank")
} }
onLoadedMetadata={() => setLoaded(true)}
/> />
</div> </div>
</div> </div>

View file

@ -5,6 +5,7 @@ import { Attachment } from "revolt.js/dist/api/objects";
import { determineFileSize } from '../../../../lib/fileSize'; import { determineFileSize } from '../../../../lib/fileSize';
import { AppContext } from '../../../../context/revoltjs/RevoltClient'; import { AppContext } from '../../../../context/revoltjs/RevoltClient';
import { Download, LinkExternal, File, Headphone, Video } from '@styled-icons/boxicons-regular'; import { Download, LinkExternal, File, Headphone, Video } from '@styled-icons/boxicons-regular';
import classNames from 'classnames';
interface Props { interface Props {
attachment: Attachment; attachment: Attachment;
@ -23,17 +24,15 @@ export default function AttachmentActions({ attachment }: Props) {
switch (metadata.type) { switch (metadata.type) {
case 'Image': case 'Image':
return ( return (
<div className={styles.actions}> <div className={classNames(styles.actions, styles.imageAction)}>
<div className={styles.info}>
<span className={styles.filename}>{filename}</span> <span className={styles.filename}>{filename}</span>
<span className={styles.filesize}>{metadata.width + 'x' + metadata.height} ({filesize})</span> <span className={styles.filesize}>{metadata.width + 'x' + metadata.height} ({filesize})</span>
</div> <a href={open_url} target="_blank" className={styles.iconType} >
<a href={open_url} target="_blank">
<IconButton> <IconButton>
<LinkExternal size={24} /> <LinkExternal size={24} />
</IconButton> </IconButton>
</a> </a>
<a href={download_url} download target="_blank"> <a href={download_url} className={styles.downloadIcon} download target="_blank">
<IconButton> <IconButton>
<Download size={24} /> <Download size={24} />
</IconButton> </IconButton>
@ -42,13 +41,11 @@ export default function AttachmentActions({ attachment }: Props) {
) )
case 'Audio': case 'Audio':
return ( return (
<div className={styles.actions}> <div className={classNames(styles.actions, styles.audioAction)}>
<Headphone size={24} /> <Headphone size={24} className={styles.iconType} />
<div className={styles.info}>
<span className={styles.filename}>{filename}</span> <span className={styles.filename}>{filename}</span>
<span className={styles.filesize}>{filesize}</span> <span className={styles.filesize}>{filesize}</span>
</div> <a href={download_url} className={styles.downloadIcon} download target="_blank">
<a href={download_url} download target="_blank">
<IconButton> <IconButton>
<Download size={24} /> <Download size={24} />
</IconButton> </IconButton>
@ -57,13 +54,11 @@ export default function AttachmentActions({ attachment }: Props) {
) )
case 'Video': case 'Video':
return ( return (
<div className={styles.actions}> <div className={classNames(styles.actions, styles.videoAction)}>
<Video size={24} /> <Video size={24} className={styles.iconType} />
<div className={styles.info}>
<span className={styles.filename}>{filename}</span> <span className={styles.filename}>{filename}</span>
<span className={styles.filesize}>{metadata.width + 'x' + metadata.height} ({filesize})</span> <span className={styles.filesize}>{metadata.width + 'x' + metadata.height} ({filesize})</span>
</div> <a href={download_url} className={styles.downloadIcon} download target="_blank">
<a href={download_url} download target="_blank">
<IconButton> <IconButton>
<Download size={24} /> <Download size={24} />
</IconButton> </IconButton>
@ -73,12 +68,10 @@ export default function AttachmentActions({ attachment }: Props) {
default: default:
return ( return (
<div className={styles.actions}> <div className={styles.actions}>
<File size={24} /> <File size={24} className={styles.iconType} />
<div className={styles.info}>
<span className={styles.filename}>{filename}</span> <span className={styles.filename}>{filename}</span>
<span className={styles.filesize}>{filesize}</span> <span className={styles.filesize}>{filesize}</span>
</div> <a href={download_url} className={styles.downloadIcon} download target="_blank">
<a href={download_url} download target="_blank">
<IconButton> <IconButton>
<Download size={24} /> <Download size={24} />
</IconButton> </IconButton>