mirror of
https://github.com/revoltchat/revite.git
synced 2025-01-12 15:31:26 -05:00
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:
parent
b19479f1b1
commit
02bbf78dcd
3 changed files with 89 additions and 60 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue