feat: converted quoteiconcontainer and to styled components

added support for generic file icon with consistent design. Still need to support know file types and metdata from the generic file component
pull/2757/head
William Grant 2 years ago
parent bdbdb477da
commit ff4366002b

@ -45,6 +45,7 @@
"incomingError": "Error handling incoming message",
"media": "Media",
"mediaEmptyState": "No media",
"document": "Document",
"documents": "Documents",
"documentsEmptyState": "No documents",
"today": "Today",

@ -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 (
<div className={classNames('module-quote-container')}>
<StyledQuoteContainer>
<StyledQuote
hasAttachment={Boolean(!isEmpty(attachment))}
isIncoming={isIncoming}
@ -115,10 +122,9 @@ export const Quote = (props: QuotePropsWithListener) => {
isIncoming={props.isIncoming}
showPubkeyForAuthor={isPublic}
/>
<QuoteGenericFile {...props} />
<QuoteText isIncoming={isIncoming} text={text} attachment={attachment} />
</StyledQuoteTextContent>
</StyledQuote>
</div>
</StyledQuoteContainer>
);
};

@ -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<SessionIconType, 'file' | 'image' | 'play' | 'movie' | 'microphone'>;
};
const QuoteIcon = (props: QuoteIconProps) => {
const { icon } = props;
const iconProps = icons[icon];
return (
<div className="module-quote__icon-container">
<div className="module-quote__icon-container__inner">
<div className="module-quote__icon-container__circle-background">
<div
className={classNames(
'module-quote__icon-container__icon',
`module-quote__icon-container__icon--${icon}`
)}
/>
</div>
</div>
</div>
<StyledQuoteIconContainer>
<StyledQuoteIcon>
<StyledQuoteIconBackground>
<svg viewBox={iconProps.viewBox}>
<path d={iconProps.path} />
</svg>
</StyledQuoteIconBackground>
</StyledQuoteIcon>
</StyledQuoteIconContainer>
);
};
@ -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 <QuoteIcon icon="file" />;
}
const objectUrl = getObjectUrl(thumbnail);
if (GoogleChrome.isVideoTypeSupported(contentType)) {
@ -61,6 +115,7 @@ export const QuoteIconContainer = (
<QuoteIcon icon="movie" />
);
}
if (GoogleChrome.isImageTypeSupported(contentType)) {
return objectUrl && !imageBroken ? (
<QuoteImage
@ -72,8 +127,10 @@ export const QuoteIconContainer = (
<QuoteIcon icon="image" />
);
}
if (MIME.isAudio(contentType)) {
return <QuoteIcon icon="microphone" />;
}
return null;
};

@ -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',

@ -45,6 +45,7 @@ export type LocalizerKeys =
| 'incomingError'
| 'media'
| 'mediaEmptyState'
| 'document'
| 'documents'
| 'documentsEmptyState'
| 'today'

Loading…
Cancel
Save