Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

Commit

Permalink
Update design of files list in right panel
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
  • Loading branch information
t3chguy committed Oct 14, 2024
1 parent c71dc6b commit 0c675ac
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 105 deletions.
42 changes: 10 additions & 32 deletions res/css/structures/_FilePanel.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Please see LICENSE files in the repository root for full details.

.mx_RoomView_MessageList {
width: 100%;
gap: var(--cpd-space-6x);

h2 {
display: none;
Expand All @@ -30,61 +31,38 @@ Please see LICENSE files in the repository root for full details.
we should make EventTile a base CSS class and customise it specifically
for usage in {Message,File,Notification}Panel. */

.mx_EventTile_avatar {
display: none;
}

/* Overrides for the attachment body tiles */
.mx_EventTile {
word-break: break-word;
margin-top: 10px;
padding-top: 0;

.mx_EventTile_line {
padding-inline-start: 0;
& + .mx_EventTile {
border-top: 1px solid var(--cpd-color-gray-400);
padding-top: var(--cpd-space-6x);
}

.mx_MFileBody {
line-height: 2.4rem;
.mx_EventTile_line {
padding-inline-start: 0;
}

.mx_MFileBody_download {
padding-top: $spacing-8;
display: flex;
justify-content: space-between;
font: var(--cpd-font-body-md-regular);
color: $event-timestamp-color;

.mx_MImageBody_size {
font: var(--cpd-font-body-md-regular);
text-align: right;
white-space: nowrap;
}
}

.mx_MFileBody_downloadLink {
flex: 1 1 auto;
color: $light-fg-color;
margin-top: var(--cpd-space-4x);
}

/* anchor link as wrapper */
.mx_EventTile_senderDetailsLink {
text-decoration: none;
margin-bottom: var(--cpd-space-1x);
display: block;

.mx_EventTile_senderDetails {
display: flex;
justify-content: space-between;
margin-top: -2px;
gap: var(--cpd-space-2x);

.mx_DisambiguatedProfile {
color: $event-timestamp-color; /* for ellipsis. Color of displayName and mxid is inherited */
}

.mx_MessageTimestamp {
text-align: right;
color: $secondary-content;
font: var(--cpd-font-body-sm-regular);
}
}
}
}
Expand Down
28 changes: 3 additions & 25 deletions res/css/views/messages/_MFileBody.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,7 @@ Please see LICENSE files in the repository root for full details.

.mx_MFileBody_download {
color: $accent;

.mx_MFileBody_download_icon {
/* 12px instead of 14px to better match surrounding font size */
width: 12px;
height: 12px;
mask-size: 12px;

mask-position: center;
mask-repeat: no-repeat;
mask-image: url("$(res)/img/download.svg");
background-color: $accent;
display: inline-block;
}
}

.mx_MFileBody_download a {
color: $accent;
text-decoration: none;
cursor: pointer;
height: var(--cpd-space-9x);
}

.mx_MFileBody_download object {
Expand All @@ -43,12 +25,6 @@ Please see LICENSE files in the repository root for full details.
padding: 0px;
border: none;
width: 100%;
/* Set the height of the iframe to be 1 line of text.
* Iframes don't automatically size themselves to fit their content.
* So either we have to fix the height of the iframe using CSS or
* use javascript's cross-origin postMessage API to communicate how
* big the content of the iframe is. */
height: 1.5em;
}

.mx_MFileBody_info {
Expand Down Expand Up @@ -81,6 +57,8 @@ Please see LICENSE files in the repository root for full details.
}

.mx_MFileBody_info_filename {
font: var(--cpd-font-body-md-regular);
color: var(--cpd-color-text-primary);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
Expand Down
7 changes: 5 additions & 2 deletions src/components/structures/MessagePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Please see LICENSE files in the repository root for full details.
import React, { createRef, ReactNode, TransitionEvent } from "react";
import ReactDOM from "react-dom";
import classNames from "classnames";
import { Room, MatrixClient, RoomStateEvent, EventStatus, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
import { EventStatus, EventType, MatrixClient, MatrixEvent, Room, RoomStateEvent } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { isSupportedReceiptType } from "matrix-js-sdk/src/utils";

Expand Down Expand Up @@ -818,7 +818,10 @@ export default class MessagePanel extends React.Component<IProps, IState> {
}

public wantsSeparator(prevEvent: MatrixEvent | null, mxEvent: MatrixEvent): SeparatorKind {
if (this.context.timelineRenderingType === TimelineRenderingType.ThreadsList) {
if (
this.context.timelineRenderingType === TimelineRenderingType.ThreadsList ||
this.context.timelineRenderingType === TimelineRenderingType.File
) {
return SeparatorKind.None;
}

Expand Down
58 changes: 29 additions & 29 deletions src/components/views/messages/MFileBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ Please see LICENSE files in the repository root for full details.
import React, { AllHTMLAttributes, createRef } from "react";
import { logger } from "matrix-js-sdk/src/logger";
import { MediaEventContent } from "matrix-js-sdk/src/types";
import { Button } from "@vector-im/compound-web";
import { DownloadIcon } from "@vector-im/compound-design-tokens/assets/web/icons";

import { _t } from "../../../languageHandler";
import Modal from "../../../Modal";
import AccessibleButton from "../elements/AccessibleButton";
import { mediaFromContent } from "../../../customisations/Media";
import ErrorDialog from "../dialogs/ErrorDialog";
import { fileSize, presentableTextForFile } from "../../../utils/FileUtils";
import { downloadLabelForFile, presentableTextForFile } from "../../../utils/FileUtils";
import { IBodyProps } from "./IBodyProps";
import { FileDownloader } from "../../../utils/FileDownloader";
import TextWithTooltip from "../elements/TextWithTooltip";
Expand All @@ -26,7 +28,9 @@ export let DOWNLOAD_ICON_URL: string; // cached copy of the download.svg asset f
async function cacheDownloadIcon(): Promise<void> {
if (DOWNLOAD_ICON_URL) return; // cached already
// eslint-disable-next-line @typescript-eslint/no-var-requires
const svg = await fetch(require("../../../../res/img/download.svg").default).then((r) => r.text());
const svg = await fetch(require("@vector-im/compound-design-tokens/icons/download.svg").default).then((r) =>
r.text(),
);
DOWNLOAD_ICON_URL = "data:image/svg+xml;base64," + window.btoa(svg);
}

Expand Down Expand Up @@ -125,7 +129,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
}

private get linkText(): string {
return presentableTextForFile(this.content);
return downloadLabelForFile(this.content, true);
}

private downloadFile(fileName: string, text: string): void {
Expand All @@ -138,7 +142,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
imgSrc: DOWNLOAD_ICON_URL,
imgStyle: null,
style: computedStyle(this.dummyLink.current),
textContent: _t("timeline|m.file|download_label", { text }),
textContent: text,
},
});
}
Expand Down Expand Up @@ -188,6 +192,12 @@ export default class MFileBody extends React.Component<IProps, IState> {
const contentFileSize = this.content.info ? this.content.info.size : null;
const fileType = this.content.info?.mimetype ?? "application/octet-stream";

let showDownloadLink =
!this.props.showGenericPlaceholder ||
(this.context.timelineRenderingType !== TimelineRenderingType.Room &&
this.context.timelineRenderingType !== TimelineRenderingType.Search &&
this.context.timelineRenderingType !== TimelineRenderingType.Pinned);

let placeholder: React.ReactNode = null;
if (this.props.showGenericPlaceholder) {
placeholder = (
Expand All @@ -200,6 +210,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
</TextWithTooltip>
</AccessibleButton>
);
showDownloadLink = false;
}

if (this.props.forExport) {
Expand All @@ -212,12 +223,6 @@ export default class MFileBody extends React.Component<IProps, IState> {
);
}

let showDownloadLink =
!this.props.showGenericPlaceholder ||
(this.context.timelineRenderingType !== TimelineRenderingType.Room &&
this.context.timelineRenderingType !== TimelineRenderingType.Search &&
this.context.timelineRenderingType !== TimelineRenderingType.Pinned);

if (this.context.timelineRenderingType === TimelineRenderingType.Thread) {
showDownloadLink = false;
}
Expand All @@ -235,9 +240,9 @@ export default class MFileBody extends React.Component<IProps, IState> {
{placeholder}
{showDownloadLink && (
<div className="mx_MFileBody_download">
<AccessibleButton onClick={this.decryptFile}>
{_t("timeline|m.file|decrypt_label", { text: this.linkText })}
</AccessibleButton>
<Button size="sm" Icon={DownloadIcon} onClick={this.decryptFile}>
{_t(`timeline|${this.content.msgtype}|decrypt_label`)}
</Button>
</div>
)}
</span>
Expand All @@ -254,14 +259,13 @@ export default class MFileBody extends React.Component<IProps, IState> {
<div className="mx_MFileBody_download">
<div aria-hidden style={{ display: "none" }}>
{/*
* Add dummy copy of the "a" tag
* We'll use it to learn how the download link
* Add dummy copy of the button
* We'll use it to learn how the download button
* would have been styled if it was rendered inline.
*/}
{/* this violates multiple eslint rules
so ignore it completely */}
{/* eslint-disable-next-line */}
<a ref={this.dummyLink} />
<Button size="sm" Icon={DownloadIcon} as="a" ref={this.dummyLink} />
</div>
{/*
TODO: Move iframe (and dummy link) into FileDownloader.
Expand All @@ -283,7 +287,10 @@ export default class MFileBody extends React.Component<IProps, IState> {
</span>
);
} else if (contentUrl) {
const downloadProps: AllHTMLAttributes<HTMLAnchorElement> = {
const downloadProps: Pick<
AllHTMLAttributes<HTMLAnchorElement>,
"target" | "rel" | "href" | "onClick" | "download"
> = {
target: "_blank",
rel: "noreferrer noopener",

Expand Down Expand Up @@ -332,25 +339,18 @@ export default class MFileBody extends React.Component<IProps, IState> {
{placeholder}
{showDownloadLink && (
<div className="mx_MFileBody_download">
<a {...downloadProps}>
<span className="mx_MFileBody_download_icon" />
{_t("timeline|m.file|download_label", { text: this.linkText })}
</a>
{this.context.timelineRenderingType === TimelineRenderingType.File && (
<div className="mx_MImageBody_size">
{this.content.info?.size ? fileSize(this.content.info.size) : ""}
</div>
)}
<Button size="sm" Icon={DownloadIcon} as="a" {...downloadProps}>
{this.linkText}
</Button>
</div>
)}
</span>
);
} else {
const extra = this.linkText ? ": " + this.linkText : "";
return (
<span className="mx_MFileBody">
{placeholder}
{_t("timeline|m.file|error_invalid", { extra: extra })}
{_t("timeline|m.file|error_invalid")}
</span>
);
}
Expand Down
25 changes: 14 additions & 11 deletions src/components/views/rooms/EventTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,9 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
// no avatar or sender profile for continuation messages and call tiles
avatarSize = null;
needsSenderProfile = false;
} else if (this.context.timelineRenderingType === TimelineRenderingType.File) {
avatarSize = "20px";
needsSenderProfile = true;
} else {
avatarSize = "30px";
needsSenderProfile = true;
Expand Down Expand Up @@ -1351,6 +1354,17 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
"data-scroll-tokens": scrollToken,
},
[
<a
className="mx_EventTile_senderDetailsLink"
key="mx_EventTile_senderDetailsLink"
href={permalink}
onClick={this.onPermalinkClicked}
>
<div className="mx_EventTile_senderDetails" onContextMenu={this.onTimestampContextMenu}>
{avatar}
{sender}
</div>
</a>,
<div className={lineClasses} key="mx_EventTile_line" onContextMenu={this.onContextMenu}>
{this.renderContextMenu()}
{renderTile(
Expand All @@ -1371,17 +1385,6 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
this.context.showHiddenEvents,
)}
</div>,
<a
className="mx_EventTile_senderDetailsLink"
key="mx_EventTile_senderDetailsLink"
href={permalink}
onClick={this.onPermalinkClicked}
>
<div className="mx_EventTile_senderDetails" onContextMenu={this.onTimestampContextMenu}>
{sender}
{timestamp}
</div>
</a>,
],
);
}
Expand Down
12 changes: 9 additions & 3 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -3294,6 +3294,8 @@
"unable_to_find": "Tried to load a specific point in this room's timeline, but was unable to find it."
},
"m.audio": {
"decrypt_label": "Decrypt audio",
"download_label": "Download audio",
"error_downloading_audio": "Error downloading audio",
"error_processing_audio": "Error processing audio message",
"error_processing_voice_message": "Error processing voice message",
Expand Down Expand Up @@ -3329,12 +3331,14 @@
"voice_call_unsupported": "%(senderName)s placed a voice call. (not supported by this browser)"
},
"m.file": {
"decrypt_label": "Decrypt %(text)s",
"download_label": "Download %(text)s",
"decrypt_label": "Decrypt file",
"download_label": "Download file",
"error_decrypting": "Error decrypting attachment",
"error_invalid": "Invalid file%(extra)s"
"error_invalid": "Invalid file"
},
"m.image": {
"decrypt_label": "Decrypt image",
"download_label": "Download image",
"error": "Unable to show image due to error",
"error_decrypting": "Error decrypting image",
"error_downloading": "Error downloading image",
Expand Down Expand Up @@ -3471,6 +3475,8 @@
"m.room.topic": "%(senderDisplayName)s changed the topic to \"%(topic)s\".",
"m.sticker": "%(senderDisplayName)s sent a sticker.",
"m.video": {
"decrypt_label": "Decrypt video",
"download_label": "Download video",
"error_decrypting": "Error decrypting video"
},
"m.widget": {
Expand Down
6 changes: 3 additions & 3 deletions src/usercontent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ function remoteRender(event: MessageEvent): void {
// @ts-ignore
img.style = data.imgStyle;
} else {
img.style.width = "12px";
img.style.height = "12px";
img.style.webkitMaskSize = "12px";
img.style.width = "20px";
img.style.height = "20px";
img.style.webkitMaskSize = "20px";
img.style.webkitMaskPosition = "center";
img.style.webkitMaskRepeat = "no-repeat";
img.style.display = "inline-block";
Expand Down
Loading

0 comments on commit 0c675ac

Please sign in to comment.