diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index c0effc14e..0df30a7e1 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -45,6 +45,7 @@
"incomingError": "Error handling incoming message",
"media": "Media",
"mediaEmptyState": "No media",
+ "document": "Document",
"documents": "Documents",
"documentsEmptyState": "No documents",
"today": "Today",
diff --git a/ts/components/conversation/message/message-content/quote/Quote.tsx b/ts/components/conversation/message/message-content/quote/Quote.tsx
index f7453b2bb..fd3d9ce6f 100644
--- a/ts/components/conversation/message/message-content/quote/Quote.tsx
+++ b/ts/components/conversation/message/message-content/quote/Quote.tsx
@@ -1,5 +1,4 @@
import React, { useState, MouseEvent } from 'react';
-import classNames from 'classnames';
import * as MIME from '../../../../../types/MIME';
@@ -7,7 +6,6 @@ import { useSelector } from 'react-redux';
import { isPublicGroupConversation } from '../../../../../state/selectors/conversations';
import { QuoteAuthor } from './QuoteAuthor';
-import { QuoteGenericFile } from './QuoteGenericFile';
import { QuoteText } from './QuoteText';
import { QuoteIconContainer } from './QuoteIconContainer';
import styled from 'styled-components';
@@ -54,6 +52,11 @@ function validateQuote(quote: QuotePropsWithoutListener): boolean {
return false;
}
+const StyledQuoteContainer = styled.div`
+ min-width: 300px; // if the quoted content is small it doesn't look very good so we set a minimum
+ padding-right: var(--margins-xs);
+`;
+
const StyledQuote = styled.div<{
hasAttachment: boolean;
isIncoming: boolean;
@@ -64,7 +67,7 @@ const StyledQuote = styled.div<{
display: flex;
flex-direction: row;
align-items: stretch;
- overflow: hidden;
+ margin: ${props => (props.hasAttachment ? 'var(--margins-md)' : 'var(--margins-xs)')} 0;
${props => !props.hasAttachment && 'border-left: 4px solid;'}
border-color: ${props =>
props.isIncoming
@@ -78,6 +81,10 @@ const StyledQuoteTextContent = styled.div`
padding-inline-start: 10px;
padding-inline-end: 10px;
max-width: 100%;
+
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
`;
export const Quote = (props: QuotePropsWithListener) => {
@@ -95,7 +102,7 @@ export const Quote = (props: QuotePropsWithListener) => {
const { isIncoming, attachment, text, onClick } = props;
return (
-
+
{
isIncoming={props.isIncoming}
showPubkeyForAuthor={isPublic}
/>
-
-
+
);
};
diff --git a/ts/components/conversation/message/message-content/quote/QuoteIconContainer.tsx b/ts/components/conversation/message/message-content/quote/QuoteIconContainer.tsx
index 330dde711..db08b8203 100644
--- a/ts/components/conversation/message/message-content/quote/QuoteIconContainer.tsx
+++ b/ts/components/conversation/message/message-content/quote/QuoteIconContainer.tsx
@@ -3,9 +3,10 @@ import { Attachment, QuotePropsWithoutListener } from './Quote';
import { GoogleChrome } from '../../../../../util';
import { MIME } from '../../../../../types';
-import { noop } from 'lodash';
+import { isEmpty, noop } from 'lodash';
import { QuoteImage } from './QuoteImage';
-import classNames from 'classnames';
+import styled from 'styled-components';
+import { SessionIconType, icons } from '../../../../icon';
function getObjectUrl(thumbnail: Attachment | undefined): string | undefined {
if (thumbnail && thumbnail.objectUrl) {
@@ -15,22 +16,66 @@ function getObjectUrl(thumbnail: Attachment | undefined): string | undefined {
return;
}
-const QuoteIcon = (props: any) => {
+const StyledQuoteIconContainer = styled.div`
+ flex: initial;
+ min-width: 54px;
+ width: 54px;
+ max-height: 54px;
+ position: relative;
+`;
+
+const StyledQuoteIcon = styled.div`
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+
+ text-align: center;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+`;
+
+const StyledQuoteIconBackground = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ height: 54px;
+ width: 54px;
+ border-radius: var(--margins-sm);
+ background-color: var(--message-link-preview-background-color);
+
+ &:hover {
+ background-color: var(--message-link-preview-background-color);
+ }
+
+ svg {
+ width: 29px;
+ height: 29px;
+ fill: currentColor;
+ }
+`;
+
+type QuoteIconProps = {
+ icon: Extract;
+};
+
+const QuoteIcon = (props: QuoteIconProps) => {
const { icon } = props;
+ const iconProps = icons[icon];
return (
-
+
+
+
+
+
+
+
);
};
@@ -42,11 +87,20 @@ export const QuoteIconContainer = (
) => {
const { attachment, imageBroken, handleImageErrorBound } = props;
- if (!attachment) {
+ if (!attachment || isEmpty(attachment)) {
return null;
}
const { contentType, thumbnail } = attachment;
+ const isGenericFile =
+ !GoogleChrome.isVideoTypeSupported(contentType) &&
+ !GoogleChrome.isImageTypeSupported(contentType) &&
+ !MIME.isAudio(contentType);
+
+ if (isGenericFile) {
+ return ;
+ }
+
const objectUrl = getObjectUrl(thumbnail);
if (GoogleChrome.isVideoTypeSupported(contentType)) {
@@ -61,6 +115,7 @@ export const QuoteIconContainer = (
);
}
+
if (GoogleChrome.isImageTypeSupported(contentType)) {
return objectUrl && !imageBroken ? (
);
}
+
if (MIME.isAudio(contentType)) {
return ;
}
+
return null;
};
diff --git a/ts/components/icon/Icons.tsx b/ts/components/icon/Icons.tsx
index 5eebb10db..9f1f2c6b2 100644
--- a/ts/components/icon/Icons.tsx
+++ b/ts/components/icon/Icons.tsx
@@ -30,12 +30,14 @@ export type SessionIconType =
| 'gear'
| 'group'
| 'hangup'
+ | 'image'
| 'info'
| 'link'
| 'messageRequest'
| 'microphone'
| 'microphoneFull'
| 'moon'
+ | 'movie'
| 'mute'
| 'oxen'
| 'externalLink'
@@ -268,6 +270,12 @@ export const icons = {
viewBox: '0 0 1000 1000',
ratio: 1,
},
+ image: {
+ path:
+ 'M8.5,13.5L11,16.5L14.5,12L19,18H5M21,19V5C21,3.89 20.1,3 19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19Z',
+ viewBox: '0 0 24 24',
+ ratio: 1,
+ },
info: {
path:
'M17.5,2.4c-1.82-1.5-4.21-2.1-6.57-1.64c-3.09,0.6-5.57,3.09-6.15,6.19c-0.4,2.1,0.04,4.21,1.22,5.95 C7.23,14.7,8,16.41,8.36,18.12c0.17,0.81,0.89,1.41,1.72,1.41h4.85c0.83,0,1.55-0.59,1.72-1.42c0.37-1.82,1.13-3.55,2.19-4.99 c1-1.36,1.53-2.96,1.53-4.65C20.37,6.11,19.32,3.9,17.5,2.4z M17.47,12.11c-1.21,1.64-2.07,3.6-2.55,5.72l-4.91-0.05 c-0.4-1.93-1.25-3.84-2.62-5.84c-0.93-1.36-1.27-3.02-0.95-4.67c0.46-2.42,2.39-4.37,4.81-4.83c0.41-0.08,0.82-0.12,1.23-0.12 c1.44,0,2.82,0.49,3.94,1.4c1.43,1.18,2.25,2.91,2.25,4.76C18.67,9.79,18.25,11.04,17.47,12.11z M15.94,20.27H9.61c-0.47,0-0.85,0.38-0.85,0.85s0.38,0.85,0.85,0.85h6.33c0.47,0,0.85-0.38,0.85-0.85 S16.41,20.27,15.94,20.27z M15.94,22.7H9.61c-0.47,0-0.85,0.38-0.85,0.85s0.38,0.85,0.85,0.85h6.33c0.47,0,0.85-0.38,0.85-0.85 S16.41,22.7,15.94,22.7z M12.5,3.28c-2.89,0-5.23,2.35-5.23,5.23c0,0.47,0.38,0.85,0.85,0.85s0.85-0.38,0.85-0.85 c0-1.95,1.59-3.53,3.54-3.53c0.47,0,0.85-0.38,0.85-0.85S12.97,3.28,12.5,3.28z',
@@ -304,6 +312,12 @@ export const icons = {
viewBox: '0 0 20 21',
ratio: 1,
},
+ movie: {
+ path:
+ 'M18,4L20,8H17L15,4H13L15,8H12L10,4H8L10,8H7L5,4H4A2,2 0 0,0 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V4H18Z',
+ viewBox: '0 0 24 24',
+ ratio: 1,
+ },
mute: {
path:
'M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zM12,6.5c2.49,0 4,2.02 4,4.5v0.1l2,2L18,11c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68c-0.24,0.06 -0.47,0.15 -0.69,0.23l1.64,1.64c0.18,-0.02 0.36,-0.05 0.55,-0.05zM5.41,3.35L4,4.76l2.81,2.81C6.29,8.57 6,9.74 6,11v5l-2,2v1h14.24l1.74,1.74 1.41,-1.41L5.41,3.35zM16,17L8,17v-6c0,-0.68 0.12,-1.32 0.34,-1.9L16,16.76L16,17z',
diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts
index 5c6900f7b..76fcb30bb 100644
--- a/ts/types/LocalizerKeys.ts
+++ b/ts/types/LocalizerKeys.ts
@@ -45,6 +45,7 @@ export type LocalizerKeys =
| 'incomingError'
| 'media'
| 'mediaEmptyState'
+ | 'document'
| 'documents'
| 'documentsEmptyState'
| 'today'