Update to new design for avatars: individual/group icons/colors
And two initials.
This commit is contained in:
parent
cf16ced91c
commit
8f3e3b7aaf
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 51.3 (57544) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Group/group-28</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<path d="M18.7272727,13.2857143 C20.6890909,13.2857143 22.2609091,11.6585714 22.2609091,9.64285714 C22.2609091,7.62714286 20.6890909,6 18.7272727,6 C16.7654545,6 15.1818182,7.62714286 15.1818182,9.64285714 C15.1818182,11.6585714 16.7654545,13.2857143 18.7272727,13.2857143 Z M9.27272727,13.2857143 C11.2345455,13.2857143 12.8063636,11.6585714 12.8063636,9.64285714 C12.8063636,7.62714286 11.2345455,6 9.27272727,6 C7.31090909,6 5.72727273,7.62714286 5.72727273,9.64285714 C5.72727273,11.6585714 7.31090909,13.2857143 9.27272727,13.2857143 Z M9.27272727,15.7142857 C6.51909091,15.7142857 1,17.135 1,19.9642857 L1,23 L17.5454545,23 L17.5454545,19.9642857 C17.5454545,17.135 12.0263636,15.7142857 9.27272727,15.7142857 Z M18.7272727,15.7142857 C18.3845455,15.7142857 17.9945455,15.7385714 17.5809091,15.775 C18.9518182,16.795 19.9090909,18.1671429 19.9090909,19.9642857 L19.9090909,23 L27,23 L27,19.9642857 C27,17.135 21.4809091,15.7142857 18.7272727,15.7142857 Z" id="path-1"></path>
|
||||
<rect id="path-3" x="0" y="0" width="28" height="28"></rect>
|
||||
</defs>
|
||||
<g id="Group/group-28" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<mask id="mask-2" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
<use id="Shape" fill="#000000" fill-rule="nonzero" xlink:href="#path-1"></use>
|
||||
<g id="Color/UI/Black" mask="url(#mask-2)">
|
||||
<mask id="mask-4" fill="white">
|
||||
<use xlink:href="#path-3"></use>
|
||||
</mask>
|
||||
<use id="fill" fill="#000000" fill-rule="evenodd" xlink:href="#path-3"></use>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 51.3 (57544) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Profile/profile-28</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<path d="M14,14 C16.7625,14 19,11.7625 19,9 C19,6.2375 16.7625,4 14,4 C11.2375,4 9,6.2375 9,9 C9,11.7625 11.2375,14 14,14 Z M14,16.5 C10.6625,16.5 4,18.175 4,21.5 L4,24 L24,24 L24,21.5 C24,18.175 17.3375,16.5 14,16.5 Z" id="path-1"></path>
|
||||
<rect id="path-3" x="0" y="0" width="28" height="28"></rect>
|
||||
</defs>
|
||||
<g id="Profile/profile-28" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<mask id="mask-2" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
<use id="Shape" fill="#000000" fill-rule="nonzero" xlink:href="#path-1"></use>
|
||||
<g id="Color/UI/Black" mask="url(#mask-2)">
|
||||
<mask id="mask-4" fill="white">
|
||||
<use xlink:href="#path-3"></use>
|
||||
</mask>
|
||||
<use id="fill" fill="#000000" fill-rule="evenodd" xlink:href="#path-3"></use>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -174,8 +174,6 @@
|
|||
format() {
|
||||
const { format } = PhoneNumber;
|
||||
const regionCode = storage.get('regionCode');
|
||||
|
||||
const avatar = this.getAvatar();
|
||||
const color = this.getColor();
|
||||
|
||||
return {
|
||||
|
@ -183,7 +181,7 @@
|
|||
ourRegionCode: regionCode,
|
||||
}),
|
||||
color,
|
||||
avatarPath: avatar ? avatar.url : null,
|
||||
avatarPath: this.getAvatarPath(),
|
||||
name: this.getName(),
|
||||
profileName: this.getProfileName(),
|
||||
title: this.getTitle(),
|
||||
|
@ -192,6 +190,7 @@
|
|||
getPropsForListItem() {
|
||||
const result = {
|
||||
...this.format(),
|
||||
conversationType: this.isPrivate() ? 'direct' : 'group',
|
||||
|
||||
lastUpdated: this.get('timestamp'),
|
||||
unreadCount: this.get('unreadCount') || 0,
|
||||
|
@ -1369,6 +1368,15 @@
|
|||
const { migrateColor } = Util;
|
||||
return migrateColor(this.get('color'));
|
||||
},
|
||||
getAvatarPath() {
|
||||
const avatar = this.get('avatar') || this.get('profileAvatar');
|
||||
|
||||
if (avatar && avatar.path) {
|
||||
return getAbsoluteAttachmentPath(avatar.path);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
getAvatar() {
|
||||
const title = this.get('name');
|
||||
const color = this.getColor();
|
||||
|
|
|
@ -300,7 +300,6 @@
|
|||
const regionCode = storage.get('regionCode');
|
||||
|
||||
const contactModel = this.findContact(phoneNumber);
|
||||
const avatar = contactModel ? contactModel.getAvatar() : null;
|
||||
const color = contactModel ? contactModel.getColor() : null;
|
||||
|
||||
return {
|
||||
|
@ -308,7 +307,7 @@
|
|||
ourRegionCode: regionCode,
|
||||
}),
|
||||
color,
|
||||
avatarPath: avatar ? avatar.url : null,
|
||||
avatarPath: contactModel ? contactModel.getAvatarPath() : null,
|
||||
name: contactModel ? contactModel.getName() : null,
|
||||
profileName: contactModel ? contactModel.getProfileName() : null,
|
||||
title: contactModel ? contactModel.getTitle() : null,
|
||||
|
@ -394,8 +393,9 @@
|
|||
const contact = this.findAndFormatContact(phoneNumber);
|
||||
const contactModel = this.findContact(phoneNumber);
|
||||
|
||||
const authorAvatar = contactModel ? contactModel.getAvatar() : null;
|
||||
const authorAvatarPath = authorAvatar ? authorAvatar.url : null;
|
||||
const authorAvatarPath = contactModel
|
||||
? contactModel.getAvatarPath()
|
||||
: null;
|
||||
|
||||
const expirationLength = this.get('expireTimer') * 1000;
|
||||
const expireTimerStart = this.get('expirationStartTimestamp');
|
||||
|
@ -530,10 +530,16 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
const { format } = PhoneNumber;
|
||||
const regionCode = storage.get('regionCode');
|
||||
|
||||
const conversation = this.getConversation();
|
||||
const { author, id, referencedMessageNotFound } = quote;
|
||||
const contact = author && ConversationController.get(author);
|
||||
|
||||
const authorPhoneNumber = author;
|
||||
const authorPhoneNumber = format(author, {
|
||||
ourRegionCode: regionCode,
|
||||
});
|
||||
const authorProfileName = contact ? contact.getProfileName() : null;
|
||||
const authorName = contact ? contact.getName() : null;
|
||||
const isFromMe = contact ? contact.id === this.OUR_NUMBER : false;
|
||||
|
@ -556,6 +562,7 @@
|
|||
authorPhoneNumber,
|
||||
authorProfileName,
|
||||
authorName,
|
||||
conversationColor: conversation && conversation.getColor(),
|
||||
onClick,
|
||||
referencedMessageNotFound,
|
||||
};
|
||||
|
|
|
@ -25,9 +25,6 @@
|
|||
this.contactView = null;
|
||||
}
|
||||
|
||||
const avatar = this.model.getAvatar();
|
||||
const avatarPath = avatar && avatar.url;
|
||||
const color = avatar && avatar.color;
|
||||
const isMe = this.ourNumber === this.model.id;
|
||||
|
||||
this.contactView = new Whisper.ReactWrapperView({
|
||||
|
@ -35,8 +32,8 @@
|
|||
Component: window.Signal.Components.ContactListItem,
|
||||
props: {
|
||||
isMe,
|
||||
color,
|
||||
avatarPath,
|
||||
color: this.model.getColor(),
|
||||
avatarPath: this.model.getAvatarPath(),
|
||||
phoneNumber: this.model.getNumber(),
|
||||
name: this.model.getName(),
|
||||
profileName: this.model.getProfileName(),
|
||||
|
|
|
@ -145,8 +145,6 @@
|
|||
});
|
||||
|
||||
const getHeaderProps = () => {
|
||||
const avatar = this.model.getAvatar();
|
||||
const avatarPath = avatar ? avatar.url : null;
|
||||
const expireTimer = this.model.get('expireTimer');
|
||||
const expirationSettingName = expireTimer
|
||||
? Whisper.ExpirationTimerOptions.getName(expireTimer || 0)
|
||||
|
@ -158,7 +156,7 @@
|
|||
phoneNumber: this.model.getNumber(),
|
||||
profileName: this.model.getProfileName(),
|
||||
color: this.model.getColor(),
|
||||
avatarPath,
|
||||
avatarPath: this.model.getAvatarPath(),
|
||||
isVerified: this.model.isVerified(),
|
||||
isMe: this.model.isMe(),
|
||||
isGroup: !this.model.isPrivate(),
|
||||
|
@ -1401,6 +1399,7 @@
|
|||
}
|
||||
|
||||
const message = new Whisper.Message({
|
||||
conversationId: this.model.id,
|
||||
quote: this.quote,
|
||||
});
|
||||
message.quotedMessage = this.quotedMessage;
|
||||
|
|
|
@ -560,74 +560,6 @@
|
|||
// This accounts for the weird extra 3px we get at the bottom of messages
|
||||
bottom: -3px;
|
||||
right: calc(100% + 4px);
|
||||
|
||||
img {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
border-radius: 18px;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.module-message__author-default-avatar {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: calc(100% + 4px);
|
||||
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
border-radius: 18px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
|
||||
// Default, in case we have no color
|
||||
background-color: $color-conversation-grey;
|
||||
}
|
||||
|
||||
.module-message__author-default-avatar--red {
|
||||
background-color: $color-conversation-red;
|
||||
}
|
||||
.module-message__author-default-avatar--deep_orange {
|
||||
background-color: $color-conversation-deep_orange;
|
||||
}
|
||||
.module-message__author-default-avatar--brown {
|
||||
background-color: $color-conversation-brown;
|
||||
}
|
||||
.module-message__author-default-avatar--pink {
|
||||
background-color: $color-conversation-pink;
|
||||
}
|
||||
.module-message__author-default-avatar--purple {
|
||||
background-color: $color-conversation-purple;
|
||||
}
|
||||
.module-message__author-default-avatar--indigo {
|
||||
background-color: $color-conversation-indigo;
|
||||
}
|
||||
.module-message__author-default-avatar--blue {
|
||||
background-color: $color-conversation-blue;
|
||||
}
|
||||
.module-message__author-default-avatar--teal {
|
||||
background-color: $color-conversation-teal;
|
||||
}
|
||||
.module-message__author-default-avatar--green {
|
||||
background-color: $color-conversation-green;
|
||||
}
|
||||
.module-message__author-default-avatar--light_green {
|
||||
background-color: $color-conversation-light_green;
|
||||
}
|
||||
.module-message__author-default-avatar--blue_grey {
|
||||
background-color: $color-conversation-blue_grey;
|
||||
}
|
||||
|
||||
.module-message__author-default-avatar__label {
|
||||
width: 100%;
|
||||
font-size: 18px;
|
||||
color: $color-white;
|
||||
|
||||
// Because it just doesn't look properly centered
|
||||
padding-right: 1px;
|
||||
}
|
||||
|
||||
// Module: Expire Timer
|
||||
|
@ -1025,37 +957,6 @@
|
|||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.module-embedded-contact__image-container {
|
||||
flex: initial;
|
||||
min-width: 50px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
object-fit: cover;
|
||||
|
||||
img {
|
||||
border-radius: 50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.module-embedded-contact__image-container__default-avatar {
|
||||
border-radius: 50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: $color-conversation-grey;
|
||||
color: $color-white;
|
||||
font-size: 25px;
|
||||
line-height: 52px;
|
||||
}
|
||||
|
||||
.module-embedded-contact__text-container {
|
||||
flex-grow: 1;
|
||||
margin-left: 8px;
|
||||
|
@ -1106,31 +1007,8 @@
|
|||
margin-right: auto;
|
||||
}
|
||||
|
||||
.module-contact-detail__image-container {
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
.module-contact-detail__avatar {
|
||||
margin-bottom: 4px;
|
||||
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
object-fit: cover;
|
||||
|
||||
img {
|
||||
border-radius: 50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.module-contact-detail__image-container__default-avatar {
|
||||
border-radius: 50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: $color-conversation-grey;
|
||||
color: $color-white;
|
||||
font-size: 50px;
|
||||
line-height: 82px;
|
||||
}
|
||||
|
||||
.module-contact-detail__contact-name {
|
||||
|
@ -1366,69 +1244,6 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-contact-list-item__avatar {
|
||||
display: inline-block;
|
||||
|
||||
img {
|
||||
height: 44px;
|
||||
width: 44px;
|
||||
border-radius: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.module-contact-list-item__avatar-default {
|
||||
height: 44px;
|
||||
width: 44px;
|
||||
border-radius: 22px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
text-align: center;
|
||||
background-color: $color-conversation-grey;
|
||||
}
|
||||
|
||||
.module-contact-list-item__avatar-default--red {
|
||||
background-color: $color-conversation-red;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--deep_orange {
|
||||
background-color: $color-conversation-deep_orange;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--brown {
|
||||
background-color: $color-conversation-brown;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--pink {
|
||||
background-color: $color-conversation-pink;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--purple {
|
||||
background-color: $color-conversation-purple;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--indigo {
|
||||
background-color: $color-conversation-indigo;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--blue {
|
||||
background-color: $color-conversation-blue;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--teal {
|
||||
background-color: $color-conversation-teal;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--green {
|
||||
background-color: $color-conversation-green;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--light_green {
|
||||
background-color: $color-conversation-light_green;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--blue_grey {
|
||||
background-color: $color-conversation-blue_grey;
|
||||
}
|
||||
|
||||
.module-contact-list-item__avatar-default__label {
|
||||
width: 100%;
|
||||
color: $color-white;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.module-contact-list-item__text {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
@ -1506,54 +1321,8 @@
|
|||
max-width: 100%;
|
||||
}
|
||||
|
||||
.module-conversation-header___avatar {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
min-width: 32px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.module-conversation-header___default-avatar {
|
||||
background-color: $color-conversation-grey;
|
||||
|
||||
line-height: 32px;
|
||||
font-size: 16px;
|
||||
color: $color-white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.module-conversation-header___default-avatar--red {
|
||||
background-color: $color-conversation-red;
|
||||
}
|
||||
.module-conversation-header___default-avatar--deep_orange {
|
||||
background-color: $color-conversation-deep_orange;
|
||||
}
|
||||
.module-conversation-header___default-avatar--brown {
|
||||
background-color: $color-conversation-brown;
|
||||
}
|
||||
.module-conversation-header___default-avatar--pink {
|
||||
background-color: $color-conversation-pink;
|
||||
}
|
||||
.module-conversation-header___default-avatar--purple {
|
||||
background-color: $color-conversation-purple;
|
||||
}
|
||||
.module-conversation-header___default-avatar--indigo {
|
||||
background-color: $color-conversation-indigo;
|
||||
}
|
||||
.module-conversation-header___default-avatar--blue {
|
||||
background-color: $color-conversation-blue;
|
||||
}
|
||||
.module-conversation-header___default-avatar--teal {
|
||||
background-color: $color-conversation-teal;
|
||||
}
|
||||
.module-conversation-header___default-avatar--green {
|
||||
background-color: $color-conversation-green;
|
||||
}
|
||||
.module-conversation-header___default-avatar--light_green {
|
||||
background-color: $color-conversation-light_green;
|
||||
}
|
||||
.module-conversation-header___default-avatar--blue_grey {
|
||||
background-color: $color-conversation-blue_grey;
|
||||
.module-conversation-header__avatar {
|
||||
min-width: 28px;
|
||||
}
|
||||
|
||||
.module-conversation-header__title {
|
||||
|
@ -1565,8 +1334,8 @@
|
|||
font-weight: 300;
|
||||
color: $color-light-90;
|
||||
|
||||
// width of avatar and our 8px left margin
|
||||
max-width: calc(100% - 40px);
|
||||
// width of avatar (28px) and our 8px left margin
|
||||
max-width: calc(100% - 36px);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
@ -1674,56 +1443,6 @@
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.module-message-detail__contact__avatar {
|
||||
height: 44px;
|
||||
width: 44px;
|
||||
min-width: 44px;
|
||||
border-radius: 22px;
|
||||
}
|
||||
|
||||
.module-message-detail__contact__default-avatar {
|
||||
background-color: $color-conversation-grey;
|
||||
|
||||
line-height: 44px;
|
||||
font-size: 20px;
|
||||
color: $color-white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.module-message-detail__contact__default-avatar--red {
|
||||
background-color: $color-conversation-red;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--deep_orange {
|
||||
background-color: $color-conversation-deep_orange;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--brown {
|
||||
background-color: $color-conversation-brown;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--pink {
|
||||
background-color: $color-conversation-pink;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--purple {
|
||||
background-color: $color-conversation-purple;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--indigo {
|
||||
background-color: $color-conversation-indigo;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--blue {
|
||||
background-color: $color-conversation-blue;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--teal {
|
||||
background-color: $color-conversation-teal;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--green {
|
||||
background-color: $color-conversation-green;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--light_green {
|
||||
background-color: $color-conversation-light_green;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--blue_grey {
|
||||
background-color: $color-conversation-blue_grey;
|
||||
}
|
||||
|
||||
.module-message-detail__contact__text {
|
||||
margin-left: 10px;
|
||||
flex-grow: 1;
|
||||
|
@ -2013,58 +1732,8 @@
|
|||
|
||||
.module-conversation-list-item__avatar-container {
|
||||
position: relative;
|
||||
}
|
||||
.module-conversation-list-item__avatar {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
border-radius: 24px;
|
||||
min-width: 48px;
|
||||
|
||||
object-fit: cover;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar {
|
||||
color: white;
|
||||
font-size: 26px;
|
||||
line-height: 48px;
|
||||
text-align: center;
|
||||
|
||||
background-color: $color-conversation-grey;
|
||||
}
|
||||
|
||||
.module-conversation-list-item__default-avatar--red {
|
||||
background-color: $color-conversation-red;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--deep_orange {
|
||||
background-color: $color-conversation-deep_orange;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--brown {
|
||||
background-color: $color-conversation-brown;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--pink {
|
||||
background-color: $color-conversation-pink;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--purple {
|
||||
background-color: $color-conversation-purple;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--indigo {
|
||||
background-color: $color-conversation-indigo;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--blue {
|
||||
background-color: $color-conversation-blue;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--teal {
|
||||
background-color: $color-conversation-teal;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--green {
|
||||
background-color: $color-conversation-green;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--light_green {
|
||||
background-color: $color-conversation-light_green;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--blue_grey {
|
||||
background-color: $color-conversation-blue_grey;
|
||||
}
|
||||
|
||||
.module-conversation-list-item__unread-count {
|
||||
|
@ -2073,8 +1742,8 @@
|
|||
text-align: center;
|
||||
|
||||
padding-top: 1px;
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
|
||||
position: absolute;
|
||||
right: -6px;
|
||||
|
@ -2089,7 +1758,7 @@
|
|||
line-height: 16px;
|
||||
border-radius: 8px;
|
||||
|
||||
box-shadow: 0px 0px 1px 2px $color-white-05;
|
||||
box-shadow: 0px 0px 0px 1px $color-gray-02;
|
||||
}
|
||||
|
||||
.module-conversation-list-item__content {
|
||||
|
@ -2118,6 +1787,9 @@
|
|||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
font-weight: 300;
|
||||
color: $color-gray-90;
|
||||
}
|
||||
|
||||
.module-conversation-list-item__header__name--with-unread {
|
||||
|
@ -2137,10 +1809,13 @@
|
|||
text-overflow: ellipsis;
|
||||
|
||||
text-transform: uppercase;
|
||||
|
||||
color: $color-gray-60;
|
||||
}
|
||||
|
||||
.module-conversation-list-item__header__date--has-unread {
|
||||
font-weight: 300;
|
||||
color: $color-gray-90;
|
||||
}
|
||||
|
||||
.module-conversation-list-item__message {
|
||||
|
@ -2168,6 +1843,7 @@
|
|||
|
||||
.module-conversation-list-item__message__text--has-unread {
|
||||
font-weight: 300;
|
||||
color: $color-gray-90;
|
||||
}
|
||||
|
||||
.module-conversation-list-item__message__status-icon {
|
||||
|
@ -2208,6 +1884,167 @@
|
|||
@include color-svg('../images/error.svg', $color-core-red);
|
||||
}
|
||||
|
||||
// Module: Avatar
|
||||
|
||||
.module-avatar {
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
|
||||
img {
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.module-avatar__label {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
text-transform: uppercase;
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
.module-avatar__icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.module-avatar__icon--group {
|
||||
@include color-svg('../images/profile-group.svg', $color-white);
|
||||
}
|
||||
|
||||
.module-avatar__icon--direct {
|
||||
@include color-svg('../images/profile-individual.svg', $color-white);
|
||||
}
|
||||
|
||||
.module-avatar--28 {
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
|
||||
img {
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.module-avatar__label--28 {
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.module-avatar__icon--28 {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.module-avatar--36 {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
|
||||
img {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.module-avatar__label--36 {
|
||||
margin-top: 1px;
|
||||
width: 36px;
|
||||
font-size: 16px;
|
||||
letter-spacing: 0.19px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.module-avatar__icon--36 {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.module-avatar--48 {
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
|
||||
img {
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.module-avatar__label--48 {
|
||||
width: 48px;
|
||||
font-size: 20px;
|
||||
letter-spacing: 0.19px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.module-avatar__icon--48 {
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
}
|
||||
|
||||
.module-avatar--80 {
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
|
||||
img {
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.module-avatar__label--80 {
|
||||
width: 80px;
|
||||
font-size: 40px;
|
||||
line-height: 82px;
|
||||
}
|
||||
|
||||
.module-avatar__icon--80 {
|
||||
height: 42px;
|
||||
width: 42px;
|
||||
}
|
||||
|
||||
.module-avatar--no-image {
|
||||
background-color: $color-conversation-grey;
|
||||
}
|
||||
|
||||
.module-avatar--red {
|
||||
background-color: $color-conversation-red;
|
||||
}
|
||||
.module-avatar--deep_orange {
|
||||
background-color: $color-conversation-deep_orange;
|
||||
}
|
||||
.module-avatar--brown {
|
||||
background-color: $color-conversation-brown;
|
||||
}
|
||||
.module-avatar--pink {
|
||||
background-color: $color-conversation-pink;
|
||||
}
|
||||
.module-avatar--purple {
|
||||
background-color: $color-conversation-purple;
|
||||
}
|
||||
.module-avatar--indigo {
|
||||
background-color: $color-conversation-indigo;
|
||||
}
|
||||
.module-avatar--blue {
|
||||
background-color: $color-conversation-blue;
|
||||
}
|
||||
.module-avatar--teal {
|
||||
background-color: $color-conversation-teal;
|
||||
}
|
||||
.module-avatar--green {
|
||||
background-color: $color-conversation-green;
|
||||
}
|
||||
.module-avatar--light_green {
|
||||
background-color: $color-conversation-light_green;
|
||||
}
|
||||
.module-avatar--blue_grey {
|
||||
background-color: $color-conversation-blue_grey;
|
||||
}
|
||||
|
||||
// Third-party module: react-contextmenu
|
||||
|
||||
.react-contextmenu {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
body.dark-theme {
|
||||
background-color: $color-black;
|
||||
color: $color-gray-95;
|
||||
color: $color-gray-05;
|
||||
}
|
||||
|
||||
.dark-theme {
|
||||
|
@ -797,44 +797,6 @@ body.dark-theme {
|
|||
border: 1px solid $color-dark-60;
|
||||
}
|
||||
|
||||
.module-message__author-default-avatar--red {
|
||||
background-color: $color-conversation-red;
|
||||
}
|
||||
.module-message__author-default-avatar--deep_orange {
|
||||
background-color: $color-conversation-deep_orange;
|
||||
}
|
||||
.module-message__author-default-avatar--brown {
|
||||
background-color: $color-conversation-brown;
|
||||
}
|
||||
.module-message__author-default-avatar--pink {
|
||||
background-color: $color-conversation-pink;
|
||||
}
|
||||
.module-message__author-default-avatar--purple {
|
||||
background-color: $color-conversation-purple;
|
||||
}
|
||||
.module-message__author-default-avatar--indigo {
|
||||
background-color: $color-conversation-indigo;
|
||||
}
|
||||
.module-message__author-default-avatar--blue {
|
||||
background-color: $color-conversation-blue;
|
||||
}
|
||||
.module-message__author-default-avatar--teal {
|
||||
background-color: $color-conversation-teal;
|
||||
}
|
||||
.module-message__author-default-avatar--green {
|
||||
background-color: $color-conversation-green;
|
||||
}
|
||||
.module-message__author-default-avatar--light_green {
|
||||
background-color: $color-conversation-light_green;
|
||||
}
|
||||
.module-message__author-default-avatar--blue_grey {
|
||||
background-color: $color-conversation-blue_grey;
|
||||
}
|
||||
|
||||
.module-message__author-default-avatar__label {
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
// Module: Expire Timer
|
||||
|
||||
.module-expire-timer {
|
||||
|
@ -1076,11 +1038,6 @@ body.dark-theme {
|
|||
|
||||
// Module: Embedded Contact
|
||||
|
||||
.module-embedded-contact__image-container__default-avatar {
|
||||
background-color: $color-conversation-grey;
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
.module-embedded-contact__contact-name {
|
||||
color: $color-dark-05;
|
||||
}
|
||||
|
@ -1099,11 +1056,6 @@ body.dark-theme {
|
|||
|
||||
// Module: Contact Detail
|
||||
|
||||
.module-contact-detail__image-container__default-avatar {
|
||||
background-color: $color-conversation-grey;
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
.module-contact-detail__send-message {
|
||||
background-color: $blue;
|
||||
color: $color-white;
|
||||
|
@ -1145,7 +1097,7 @@ body.dark-theme {
|
|||
|
||||
.module-verification-notification__button {
|
||||
color: $color-signal-blue;
|
||||
background-color: $color-light-02;
|
||||
background-color: $color-gray-75;
|
||||
}
|
||||
|
||||
// Module: Verification Notification
|
||||
|
@ -1182,48 +1134,6 @@ body.dark-theme {
|
|||
color: $color-dark-30;
|
||||
}
|
||||
|
||||
.module-contact-list-item__avatar-default {
|
||||
background-color: $color-conversation-grey;
|
||||
}
|
||||
|
||||
.module-contact-list-item__avatar-default--red {
|
||||
background-color: $color-conversation-red;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--deep_orange {
|
||||
background-color: $color-conversation-deep_orange;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--brown {
|
||||
background-color: $color-conversation-brown;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--pink {
|
||||
background-color: $color-conversation-pink;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--purple {
|
||||
background-color: $color-conversation-purple;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--indigo {
|
||||
background-color: $color-conversation-indigo;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--blue {
|
||||
background-color: $color-conversation-blue;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--teal {
|
||||
background-color: $color-conversation-teal;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--green {
|
||||
background-color: $color-conversation-green;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--light_green {
|
||||
background-color: $color-conversation-light_green;
|
||||
}
|
||||
.module-contact-list-item__avatar-default--blue_grey {
|
||||
background-color: $color-conversation-blue_grey;
|
||||
}
|
||||
|
||||
.module-contact-list-item__avatar-default__label {
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
.module-contact-list-item__text__verified-icon {
|
||||
@include color-svg('../images/verified-check.svg', $color-dark-30);
|
||||
}
|
||||
|
@ -1240,45 +1150,6 @@ body.dark-theme {
|
|||
@include color-svg('../images/back.svg', $color-dark-05);
|
||||
}
|
||||
|
||||
.module-conversation-header___default-avatar {
|
||||
background-color: $color-conversation-grey;
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
.module-conversation-header___default-avatar--red {
|
||||
background-color: $color-conversation-red;
|
||||
}
|
||||
.module-conversation-header___default-avatar--deep_orange {
|
||||
background-color: $color-conversation-deep_orange;
|
||||
}
|
||||
.module-conversation-header___default-avatar--brown {
|
||||
background-color: $color-conversation-brown;
|
||||
}
|
||||
.module-conversation-header___default-avatar--pink {
|
||||
background-color: $color-conversation-pink;
|
||||
}
|
||||
.module-conversation-header___default-avatar--purple {
|
||||
background-color: $color-conversation-purple;
|
||||
}
|
||||
.module-conversation-header___default-avatar--indigo {
|
||||
background-color: $color-conversation-indigo;
|
||||
}
|
||||
.module-conversation-header___default-avatar--blue {
|
||||
background-color: $color-conversation-blue;
|
||||
}
|
||||
.module-conversation-header___default-avatar--teal {
|
||||
background-color: $color-conversation-teal;
|
||||
}
|
||||
.module-conversation-header___default-avatar--green {
|
||||
background-color: $color-conversation-green;
|
||||
}
|
||||
.module-conversation-header___default-avatar--light_green {
|
||||
background-color: $color-conversation-light_green;
|
||||
}
|
||||
.module-conversation-header___default-avatar--blue_grey {
|
||||
background-color: $color-conversation-blue_grey;
|
||||
}
|
||||
|
||||
.module-conversation-header__title {
|
||||
color: $color-dark-05;
|
||||
}
|
||||
|
@ -1308,45 +1179,6 @@ body.dark-theme {
|
|||
border: solid 1px $color-light-35;
|
||||
}
|
||||
|
||||
.module-message-detail__contact__default-avatar {
|
||||
background-color: $color-conversation-grey;
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
.module-message-detail__contact__default-avatar--red {
|
||||
background-color: $color-conversation-red;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--deep_orange {
|
||||
background-color: $color-conversation-deep_orange;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--brown {
|
||||
background-color: $color-conversation-brown;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--pink {
|
||||
background-color: $color-conversation-pink;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--purple {
|
||||
background-color: $color-conversation-purple;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--indigo {
|
||||
background-color: $color-conversation-indigo;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--blue {
|
||||
background-color: $color-conversation-blue;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--teal {
|
||||
background-color: $color-conversation-teal;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--green {
|
||||
background-color: $color-conversation-green;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--light_green {
|
||||
background-color: $color-conversation-light_green;
|
||||
}
|
||||
.module-message-detail__contact__default-avatar--blue_grey {
|
||||
background-color: $color-conversation-blue_grey;
|
||||
}
|
||||
|
||||
.module-message-detail__contact__error {
|
||||
color: $color-core-red;
|
||||
}
|
||||
|
@ -1437,43 +1269,30 @@ body.dark-theme {
|
|||
background-color: $color-dark-70;
|
||||
}
|
||||
|
||||
.module-conversation-list-item__default-avatar {
|
||||
color: white;
|
||||
background-color: $color-conversation-grey;
|
||||
.module-conversation-list-item__unread-count {
|
||||
color: $color-white;
|
||||
background-color: $color-signal-blue;
|
||||
box-shadow: 0px 0px 0px 1px $color-dark-85;
|
||||
}
|
||||
|
||||
.module-conversation-list-item__default-avatar--red {
|
||||
background-color: $color-conversation-red;
|
||||
.module-conversation-list-item__header__name {
|
||||
color: $color-gray-05;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--deep_orange {
|
||||
background-color: $color-conversation-deep_orange;
|
||||
|
||||
.module-conversation-list-item__header__timestamp {
|
||||
color: $color-gray-25;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--brown {
|
||||
background-color: $color-conversation-brown;
|
||||
|
||||
.module-conversation-list-item__header__date--has-unread {
|
||||
color: $color-gray-05;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--pink {
|
||||
background-color: $color-conversation-pink;
|
||||
|
||||
.module-conversation-list-item__message__text {
|
||||
color: $color-gray-25;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--purple {
|
||||
background-color: $color-conversation-purple;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--indigo {
|
||||
background-color: $color-conversation-indigo;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--blue {
|
||||
background-color: $color-conversation-blue;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--teal {
|
||||
background-color: $color-conversation-teal;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--green {
|
||||
background-color: $color-conversation-green;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--light_green {
|
||||
background-color: $color-conversation-light_green;
|
||||
}
|
||||
.module-conversation-list-item__default-avatar--blue_grey {
|
||||
background-color: $color-conversation-blue_grey;
|
||||
|
||||
.module-conversation-list-item__message__text--has-unread {
|
||||
color: $color-gray-05;
|
||||
}
|
||||
|
||||
.module-conversation-list-item__message__status-icon--sending {
|
||||
|
@ -1492,6 +1311,58 @@ body.dark-theme {
|
|||
width: 18px;
|
||||
}
|
||||
|
||||
// Module: Avatar
|
||||
|
||||
.module-avatar__label {
|
||||
color: $color-gray-05;
|
||||
}
|
||||
|
||||
.module-avatar__icon--group {
|
||||
@include color-svg('../images/profile-group.svg', $color-gray-05);
|
||||
}
|
||||
|
||||
.module-avatar__icon--direct {
|
||||
@include color-svg('../images/profile-individual.svg', $color-gray-05);
|
||||
}
|
||||
|
||||
.module-avatar--no-image {
|
||||
background-color: $color-conversation-grey-shade;
|
||||
}
|
||||
|
||||
.module-avatar--red {
|
||||
background-color: $color-conversation-red-shade;
|
||||
}
|
||||
.module-avatar--deep_orange {
|
||||
background-color: $color-conversation-deep_orange-shade;
|
||||
}
|
||||
.module-avatar--brown {
|
||||
background-color: $color-conversation-brown-shade;
|
||||
}
|
||||
.module-avatar--pink {
|
||||
background-color: $color-conversation-pink-shade;
|
||||
}
|
||||
.module-avatar--purple {
|
||||
background-color: $color-conversation-purple-shade;
|
||||
}
|
||||
.module-avatar--indigo {
|
||||
background-color: $color-conversation-indigo-shade;
|
||||
}
|
||||
.module-avatar--blue {
|
||||
background-color: $color-conversation-blue-shade;
|
||||
}
|
||||
.module-avatar--teal {
|
||||
background-color: $color-conversation-teal-shade;
|
||||
}
|
||||
.module-avatar--green {
|
||||
background-color: $color-conversation-green-shade;
|
||||
}
|
||||
.module-avatar--light_green {
|
||||
background-color: $color-conversation-light_green-shade;
|
||||
}
|
||||
.module-avatar--blue_grey {
|
||||
background-color: $color-conversation-blue_grey-shade;
|
||||
}
|
||||
|
||||
// Third-party module: react-contextmenu
|
||||
|
||||
.react-contextmenu {
|
||||
|
|
|
@ -0,0 +1,299 @@
|
|||
### With avatar
|
||||
|
||||
```jsx
|
||||
<Avatar
|
||||
size={28}
|
||||
color="pink"
|
||||
name="John Smith"
|
||||
avatarPath={util.gifObjectUrl}
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="pink"
|
||||
name="Puppies"
|
||||
avatarPath={util.gifObjectUrl}
|
||||
conversationType="group"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
||||
|
||||
### With only name
|
||||
|
||||
```jsx
|
||||
<Avatar
|
||||
size={28}
|
||||
color="blue"
|
||||
name="John"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="green"
|
||||
name="John Smith"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="red"
|
||||
name="Puppies"
|
||||
conversationType="group"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
||||
|
||||
### Just phone number
|
||||
|
||||
```jsx
|
||||
<Avatar
|
||||
size={28}
|
||||
color="pink"
|
||||
phoneNumber="(555) 353-3433"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
||||
|
||||
### All colors
|
||||
|
||||
```jsx
|
||||
<Avatar
|
||||
size={28}
|
||||
color="red"
|
||||
name="Red"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="deep_orange"
|
||||
name="Deep Orange"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="brown"
|
||||
name="Broen"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="pink"
|
||||
name="Pink"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="purple"
|
||||
name="Purple"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="indigo"
|
||||
name="Indigo"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="blue"
|
||||
name="Blue"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="teal"
|
||||
name="Teal"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="green"
|
||||
name="Green"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="light_green"
|
||||
name="Light Green"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={28}
|
||||
color="blue_grey"
|
||||
name="Blue Grey"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
||||
|
||||
### 36px
|
||||
|
||||
```jsx
|
||||
<Avatar
|
||||
size={36}
|
||||
color="teal"
|
||||
name="John Smith"
|
||||
avatarPath={util.gifObjectUrl}
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={36}
|
||||
color="teal"
|
||||
name="John"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={36}
|
||||
color="teal"
|
||||
name="John Smith"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={36}
|
||||
color="teal"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={36}
|
||||
color="teal"
|
||||
name="Pupplies"
|
||||
conversationType="group"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
||||
|
||||
### 48px
|
||||
|
||||
```jsx
|
||||
<Avatar
|
||||
size={48}
|
||||
color="teal"
|
||||
name="John Smith"
|
||||
avatarPath={util.gifObjectUrl}
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={48}
|
||||
color="teal"
|
||||
name="John"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={48}
|
||||
color="teal"
|
||||
name="John Smith"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={48}
|
||||
color="teal"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={48}
|
||||
color="teal"
|
||||
name="Pupplies"
|
||||
conversationType="group"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
||||
|
||||
### 80px
|
||||
|
||||
```jsx
|
||||
<Avatar
|
||||
size={80}
|
||||
color="teal"
|
||||
name="John Smith"
|
||||
avatarPath={util.gifObjectUrl}
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={80}
|
||||
color="teal"
|
||||
name="John"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={80}
|
||||
color="teal"
|
||||
name="John Smith"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={80}
|
||||
color="teal"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<Avatar
|
||||
size={80}
|
||||
color="teal"
|
||||
name="Pupplies"
|
||||
conversationType="group"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
||||
|
||||
### Broken color
|
||||
|
||||
```jsx
|
||||
<Avatar
|
||||
size={28}
|
||||
color="fake"
|
||||
name="F"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
||||
|
||||
### Broken image
|
||||
|
||||
```jsx
|
||||
<Avatar
|
||||
size={28}
|
||||
color="pink"
|
||||
name="John Smith"
|
||||
avatarPath="nonexistent"
|
||||
conversationType="direct"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
||||
|
||||
### Broken image for group
|
||||
|
||||
```jsx
|
||||
<Avatar
|
||||
size={28}
|
||||
avatarPath="nonexistent"
|
||||
color="pink"
|
||||
name="Puppies"
|
||||
avatarPath="nonexistent"
|
||||
conversationType="group"
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
|
@ -0,0 +1,118 @@
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { getInitials } from '../util/getInitials';
|
||||
import { Localizer } from '../types/Util';
|
||||
|
||||
interface Props {
|
||||
avatarPath?: string;
|
||||
color?: string;
|
||||
conversationType: 'group' | 'direct';
|
||||
i18n: Localizer;
|
||||
name?: string;
|
||||
phoneNumber?: string;
|
||||
profileName?: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
interface State {
|
||||
imageBroken: boolean;
|
||||
}
|
||||
|
||||
export class Avatar extends React.Component<Props, State> {
|
||||
public handleImageErrorBound: () => void;
|
||||
|
||||
public constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.handleImageErrorBound = this.handleImageError.bind(this);
|
||||
|
||||
this.state = {
|
||||
imageBroken: false,
|
||||
};
|
||||
}
|
||||
|
||||
public handleImageError() {
|
||||
// tslint:disable-next-line no-console
|
||||
console.log('Avatar: Image failed to load; failing over to placeholder');
|
||||
this.setState({
|
||||
imageBroken: true,
|
||||
});
|
||||
}
|
||||
|
||||
public renderImage() {
|
||||
const { avatarPath, i18n, name, phoneNumber, profileName } = this.props;
|
||||
const { imageBroken } = this.state;
|
||||
const hasImage = avatarPath && !imageBroken;
|
||||
|
||||
if (!hasImage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const title = `${name || phoneNumber}${
|
||||
!name && profileName ? ` ~${profileName}` : ''
|
||||
}`;
|
||||
|
||||
return (
|
||||
<img
|
||||
onError={this.handleImageErrorBound}
|
||||
alt={i18n('contactAvatarAlt', [title])}
|
||||
src={avatarPath}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
public renderNoImage() {
|
||||
const { conversationType, name, size } = this.props;
|
||||
|
||||
const initials = getInitials(name);
|
||||
const isGroup = conversationType === 'group';
|
||||
|
||||
if (!isGroup && initials) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'module-avatar__label',
|
||||
`module-avatar__label--${size}`
|
||||
)}
|
||||
>
|
||||
{initials}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'module-avatar__icon',
|
||||
`module-avatar__icon--${conversationType}`,
|
||||
`module-avatar__icon--${size}`
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { avatarPath, color, size } = this.props;
|
||||
const { imageBroken } = this.state;
|
||||
|
||||
const hasImage = avatarPath && !imageBroken;
|
||||
|
||||
if (size !== 28 && size !== 36 && size !== 48 && size !== 80) {
|
||||
throw new Error(`Size ${size} is not supported!`);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'module-avatar',
|
||||
`module-avatar--${size}`,
|
||||
hasImage ? 'module-avatar--with-image' : 'module-avatar--no-image',
|
||||
!hasImage ? `module-avatar--${color}` : null
|
||||
)}
|
||||
>
|
||||
{hasImage ? this.renderImage() : this.renderNoImage()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Avatar } from './Avatar';
|
||||
import { Emojify } from './conversation/Emojify';
|
||||
|
||||
import { Localizer } from '../types/Util';
|
||||
|
@ -17,35 +18,28 @@ interface Props {
|
|||
onClick?: () => void;
|
||||
}
|
||||
|
||||
function getInitial(name: string): string {
|
||||
return name.trim()[0] || '#';
|
||||
}
|
||||
|
||||
export class ContactListItem extends React.Component<Props> {
|
||||
public renderAvatar({ displayName }: { displayName: string }) {
|
||||
const { avatarPath, i18n, color, name } = this.props;
|
||||
|
||||
if (avatarPath) {
|
||||
return (
|
||||
<div className="module-contact-list-item__avatar">
|
||||
<img alt={i18n('contactAvatarAlt', [displayName])} src={avatarPath} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const title = name ? getInitial(name) : '#';
|
||||
public renderAvatar() {
|
||||
const {
|
||||
avatarPath,
|
||||
i18n,
|
||||
color,
|
||||
name,
|
||||
phoneNumber,
|
||||
profileName,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'module-contact-list-item__avatar-default',
|
||||
`module-contact-list-item__avatar-default--${color}`
|
||||
)}
|
||||
>
|
||||
<div className="module-contact-list-item__avatar-default__label">
|
||||
{title}
|
||||
</div>
|
||||
</div>
|
||||
<Avatar
|
||||
avatarPath={avatarPath}
|
||||
color={color}
|
||||
conversationType="direct"
|
||||
i18n={i18n}
|
||||
name={name}
|
||||
phoneNumber={phoneNumber}
|
||||
profileName={profileName}
|
||||
size={48}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -82,7 +76,7 @@ export class ContactListItem extends React.Component<Props> {
|
|||
onClick ? 'module-contact-list-item--with-click-handler' : null
|
||||
)}
|
||||
>
|
||||
{this.renderAvatar({ displayName })}
|
||||
{this.renderAvatar()}
|
||||
<div className="module-contact-list-item__text">
|
||||
<div className="module-contact-list-item__text__name">
|
||||
<Emojify text={displayName} i18n={i18n} /> {profileElement}
|
||||
|
|
|
@ -1,154 +1,175 @@
|
|||
#### With name and profile
|
||||
|
||||
```jsx
|
||||
<ConversationListItem
|
||||
name="Someone 🔥 Somewhere"
|
||||
phoneNumber="(202) 555-0011"
|
||||
avatarPath={util.gifObjectUrl}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: "What's going on?",
|
||||
status: 'sent',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
||||
|
||||
#### Profile, with name, no avatar
|
||||
|
||||
```jsx
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Just a second',
|
||||
status: 'read',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
```
|
||||
|
||||
#### All types of status
|
||||
|
||||
```jsx
|
||||
<div>
|
||||
<util.LeftPaneContext theme={util.theme}>
|
||||
<ConversationListItem
|
||||
name="Someone 🔥 Somewhere"
|
||||
conversationType={'direct'}
|
||||
phoneNumber="(202) 555-0011"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
avatarPath={util.gifObjectUrl}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Sending',
|
||||
status: 'sending',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Sent',
|
||||
text: "What's going on?",
|
||||
status: 'sent',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### Profile, with name, no avatar
|
||||
|
||||
```jsx
|
||||
<util.LeftPaneContext theme={util.theme}>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Delivered',
|
||||
status: 'delivered',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Read',
|
||||
text: 'Just a second',
|
||||
status: 'read',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Error',
|
||||
status: 'error',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### All types of status
|
||||
|
||||
```jsx
|
||||
<util.LeftPaneContext theme={util.theme}>
|
||||
<div>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Sending',
|
||||
status: 'sending',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Sent',
|
||||
status: 'sent',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Delivered',
|
||||
status: 'delivered',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Read',
|
||||
status: 'read',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Error',
|
||||
status: 'error',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### With unread
|
||||
|
||||
```jsx
|
||||
<div>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
unreadCount={4}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Hey there!',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
unreadCount={10}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Hey there!',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
unreadCount={250}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Hey there!',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
<util.LeftPaneContext theme={util.theme}>
|
||||
<div>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
unreadCount={4}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Hey there!',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
unreadCount={10}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Hey there!',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
unreadCount={250}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Hey there!',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### Selected
|
||||
|
||||
```jsx
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
isSelected={true}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Hey there!',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<util.LeftPaneContext theme={util.theme}>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
isSelected={true}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Hey there!',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### With emoji/links in message, no status
|
||||
|
@ -156,26 +177,30 @@
|
|||
We don't want Jumbomoji or links.
|
||||
|
||||
```jsx
|
||||
<div>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Download at http://signal.org',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: '🔥',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
<util.LeftPaneContext theme={util.theme}>
|
||||
<div>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Download at http://signal.org',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: '🔥',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### Long content
|
||||
|
@ -183,72 +208,80 @@ We don't want Jumbomoji or links.
|
|||
We only show one line.
|
||||
|
||||
```jsx
|
||||
<div>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
name="Long contact name. Esquire. The third. And stuff. And more! And more!"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Normal message',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Long line. This is a really really really long line. Really really long. Because that's just how it is",
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Long line. This is a really really really long line. Really really long. Because that's just how it is",
|
||||
status: 'read',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<util.LeftPaneContext theme={util.theme}>
|
||||
<div>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
name="Long contact name. Esquire. The third. And stuff. And more! And more!"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Normal message',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Long line. This is a really really really long line. Really really long. Because that's just how it is",
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Long line. This is a really really really long line. Really really long. Because that's just how it is",
|
||||
status: 'read',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
unreadCount={8}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Long line. This is a really really really long line. Really really long. Because that's just how it is",
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Many lines. This is a many-line message.\nLine 2 is really exciting but it shouldn't be seen.\nLine three is even better.\nLine 4, well.",
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Many lines. This is a many-line message.\nLine 2 is really exciting but it shouldn't be seen.\nLine three is even better.\nLine 4, well.",
|
||||
status: 'delivered',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
unreadCount={8}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Long line. This is a really really really long line. Really really long. Because that's just how it is",
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Many lines. This is a many-line message.\nLine 2 is really exciting but it shouldn't be seen.\nLine three is even better.\nLine 4, well.",
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Many lines. This is a many-line message.\nLine 2 is really exciting but it shouldn't be seen.\nLine three is even better.\nLine 4, well.",
|
||||
status: 'delivered',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### More narrow
|
||||
|
@ -256,104 +289,119 @@ We only show one line.
|
|||
On platforms that show scrollbars all the time, this is true all the time.
|
||||
|
||||
```jsx
|
||||
<div style={{ width: '280px' }}>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
name="Long contact name. Esquire. The third. And stuff. And more! And more!"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Normal message',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Long line. This is a really really really long line. Really really long. Because that's just how it is",
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
<util.LeftPaneContext theme={util.theme}>
|
||||
<div style={{ width: '280px' }}>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
name="Long contact name. Esquire. The third. And stuff. And more! And more!"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Normal message',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text:
|
||||
"Long line. This is a really really really long line. Really really long. Because that's just how it is",
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### With various ages
|
||||
|
||||
```jsx
|
||||
<div>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 5 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Five hours ago',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 24 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'One day ago',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 7 * 24 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'One week ago',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 365 * 24 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'One year ago',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
<util.LeftPaneContext theme={util.theme}>
|
||||
<div>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'Five hours ago',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 24 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'One day ago',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 7 * 24 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'One week ago',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 365 * 24 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: 'One year ago',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### Missing data
|
||||
|
||||
```jsx
|
||||
<div>
|
||||
<ConversationListItem
|
||||
name="John"
|
||||
lastUpdated={null}
|
||||
lastMessage={{
|
||||
text: 'Missing last updated',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
name="Missing message"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: null,
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: null,
|
||||
status: 'sent',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
<util.LeftPaneContext theme={util.theme}>
|
||||
<div>
|
||||
<ConversationListItem
|
||||
name="John"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={null}
|
||||
lastMessage={{
|
||||
text: 'Missing last updated',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
name="Missing message"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: null,
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
<ConversationListItem
|
||||
phoneNumber="(202) 555-0011"
|
||||
conversationType={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
text: null,
|
||||
status: 'sent',
|
||||
}}
|
||||
onClick={() => console.log('onClick')}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Avatar } from './Avatar';
|
||||
import { MessageBody } from './conversation/MessageBody';
|
||||
import { Timestamp } from './conversation/Timestamp';
|
||||
import { ContactName } from './conversation/ContactName';
|
||||
|
@ -11,6 +12,7 @@ interface Props {
|
|||
profileName?: string;
|
||||
name?: string;
|
||||
color?: string;
|
||||
conversationType: 'group' | 'direct';
|
||||
avatarPath?: string;
|
||||
|
||||
lastUpdated: number;
|
||||
|
@ -26,50 +28,29 @@ interface Props {
|
|||
onClick?: () => void;
|
||||
}
|
||||
|
||||
function getInitial(name: string): string {
|
||||
return name.trim()[0] || '#';
|
||||
}
|
||||
|
||||
export class ConversationListItem extends React.Component<Props> {
|
||||
public renderAvatar() {
|
||||
const {
|
||||
avatarPath,
|
||||
color,
|
||||
conversationType,
|
||||
i18n,
|
||||
name,
|
||||
phoneNumber,
|
||||
profileName,
|
||||
} = this.props;
|
||||
|
||||
if (!avatarPath) {
|
||||
const initial = getInitial(name || '');
|
||||
|
||||
return (
|
||||
<div className="module-conversation-list-item__avatar-container">
|
||||
<div
|
||||
className={classNames(
|
||||
'module-conversation-list-item__avatar',
|
||||
'module-conversation-list-item__default-avatar',
|
||||
`module-conversation-list-item__default-avatar--${color}`
|
||||
)}
|
||||
>
|
||||
{initial}
|
||||
</div>
|
||||
{this.renderUnread()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const title = `${name || phoneNumber}${
|
||||
!name && profileName ? ` ~${profileName}` : ''
|
||||
}`;
|
||||
|
||||
return (
|
||||
<div className="module-conversation-list-item__avatar-container">
|
||||
<img
|
||||
className="module-conversation-list-item__avatar"
|
||||
alt={i18n('contactAvatarAlt', [title])}
|
||||
src={avatarPath}
|
||||
<Avatar
|
||||
avatarPath={avatarPath}
|
||||
color={color}
|
||||
conversationType={conversationType}
|
||||
i18n={i18n}
|
||||
name={name}
|
||||
phoneNumber={phoneNumber}
|
||||
profileName={profileName}
|
||||
size={48}
|
||||
/>
|
||||
{this.renderUnread()}
|
||||
</div>
|
||||
|
|
|
@ -207,7 +207,9 @@ export class ContactDetail extends React.Component<Props> {
|
|||
|
||||
return (
|
||||
<div className="module-contact-detail">
|
||||
{renderAvatar({ contact, i18n, module })}
|
||||
<div className="module-contact-detail__avatar">
|
||||
{renderAvatar({ contact, i18n, size: 80 })}
|
||||
</div>
|
||||
{renderName({ contact, isIncoming, module })}
|
||||
{renderContactShorthand({ contact, isIncoming, module })}
|
||||
{this.renderSendMessage({ hasSignalAccount, i18n, onSendMessage })}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Emojify } from './Emojify';
|
||||
import { Avatar } from '../Avatar';
|
||||
import { Localizer } from '../../types/Util';
|
||||
import {
|
||||
ContextMenu,
|
||||
|
@ -45,10 +45,6 @@ interface Props {
|
|||
onGoBack: () => void;
|
||||
}
|
||||
|
||||
function getInitial(name: string): string {
|
||||
return name.trim()[0] || '#';
|
||||
}
|
||||
|
||||
export class ConversationHeader extends React.Component<Props> {
|
||||
public captureMenuTriggerBound: (trigger: any) => void;
|
||||
public showMenuBound: (event: React.MouseEvent<HTMLDivElement>) => void;
|
||||
|
@ -116,37 +112,25 @@ export class ConversationHeader extends React.Component<Props> {
|
|||
avatarPath,
|
||||
color,
|
||||
i18n,
|
||||
isGroup,
|
||||
name,
|
||||
phoneNumber,
|
||||
profileName,
|
||||
} = this.props;
|
||||
|
||||
if (!avatarPath) {
|
||||
const initial = getInitial(name || '');
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'module-conversation-header___avatar',
|
||||
'module-conversation-header___default-avatar',
|
||||
`module-conversation-header___default-avatar--${color}`
|
||||
)}
|
||||
>
|
||||
{initial}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const title = `${name || phoneNumber}${
|
||||
!name && profileName ? ` ~${profileName}` : ''
|
||||
}`;
|
||||
|
||||
return (
|
||||
<img
|
||||
className="module-conversation-header___avatar"
|
||||
alt={i18n('contactAvatarAlt', [title])}
|
||||
src={avatarPath}
|
||||
/>
|
||||
<span className="module-conversation-header__avatar">
|
||||
<Avatar
|
||||
avatarPath={avatarPath}
|
||||
color={color}
|
||||
conversationType={isGroup ? 'group' : 'direct'}
|
||||
i18n={i18n}
|
||||
name={name}
|
||||
phoneNumber={phoneNumber}
|
||||
profileName={profileName}
|
||||
size={28}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Avatar } from '../Avatar';
|
||||
import { Contact, getName } from '../../types/Contact';
|
||||
|
||||
import { Localizer } from '../../types/Util';
|
||||
|
@ -41,7 +42,7 @@ export class EmbeddedContact extends React.Component<Props> {
|
|||
role="button"
|
||||
onClick={onClick}
|
||||
>
|
||||
{renderAvatar({ contact, i18n, module })}
|
||||
{renderAvatar({ contact, i18n, size: 48 })}
|
||||
<div className="module-embedded-contact__text-container">
|
||||
{renderName({ contact, isIncoming, module })}
|
||||
{renderContactShorthand({ contact, isIncoming, module })}
|
||||
|
@ -53,40 +54,29 @@ export class EmbeddedContact extends React.Component<Props> {
|
|||
|
||||
// Note: putting these below the main component so style guide picks up EmbeddedContact
|
||||
|
||||
function getInitial(name: string): string {
|
||||
return name.trim()[0] || '#';
|
||||
}
|
||||
|
||||
export function renderAvatar({
|
||||
contact,
|
||||
i18n,
|
||||
module,
|
||||
size,
|
||||
}: {
|
||||
contact: Contact;
|
||||
i18n: Localizer;
|
||||
module: string;
|
||||
size: number;
|
||||
}) {
|
||||
const { avatar } = contact;
|
||||
|
||||
const path = avatar && avatar.avatar && avatar.avatar.path;
|
||||
const avatarPath = avatar && avatar.avatar && avatar.avatar.path;
|
||||
const name = getName(contact) || '';
|
||||
|
||||
if (!path) {
|
||||
const initials = getInitial(name);
|
||||
|
||||
return (
|
||||
<div className={`module-${module}__image-container`}>
|
||||
<div className={`module-${module}__image-container__default-avatar`}>
|
||||
{initials}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`module-${module}__image-container`}>
|
||||
<img src={path} alt={i18n('contactAvatarAlt', [name])} />
|
||||
</div>
|
||||
<Avatar
|
||||
avatarPath={avatarPath}
|
||||
color="grey"
|
||||
conversationType="direct"
|
||||
i18n={i18n}
|
||||
name={name}
|
||||
size={size}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
isVideoTypeSupported,
|
||||
} from '../../util/GoogleChrome';
|
||||
|
||||
import { Avatar } from '../Avatar';
|
||||
import { MessageBody } from './MessageBody';
|
||||
import { ExpireTimer, getIncrement } from './ExpireTimer';
|
||||
import { Timestamp } from './Timestamp';
|
||||
|
@ -133,10 +134,6 @@ function canDisplayImage(attachment?: Attachment) {
|
|||
return height > 0 && height <= 4096 && width > 0 && width <= 4096;
|
||||
}
|
||||
|
||||
function getInitial(name: string): string {
|
||||
return name.trim()[0] || '#';
|
||||
}
|
||||
|
||||
function getExtension({
|
||||
fileName,
|
||||
contentType,
|
||||
|
@ -633,21 +630,17 @@ export class Message extends React.Component<Props, State> {
|
|||
|
||||
public renderAvatar() {
|
||||
const {
|
||||
authorAvatarPath,
|
||||
authorName,
|
||||
authorPhoneNumber,
|
||||
authorProfileName,
|
||||
authorAvatarPath,
|
||||
conversationColor,
|
||||
collapseMetadata,
|
||||
conversationColor,
|
||||
conversationType,
|
||||
direction,
|
||||
i18n,
|
||||
} = this.props;
|
||||
|
||||
const title = `${authorName || authorPhoneNumber}${
|
||||
!authorName && authorProfileName ? ` ~${authorProfileName}` : ''
|
||||
}`;
|
||||
|
||||
if (
|
||||
collapseMetadata ||
|
||||
conversationType !== 'group' ||
|
||||
|
@ -656,26 +649,18 @@ export class Message extends React.Component<Props, State> {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!authorAvatarPath) {
|
||||
const label = authorName ? getInitial(authorName) : '#';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'module-message__author-default-avatar',
|
||||
`module-message__author-default-avatar--${conversationColor}`
|
||||
)}
|
||||
>
|
||||
<div className="module-message__author-default-avatar__label">
|
||||
{label}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="module-message__author-avatar">
|
||||
<img alt={i18n('contactAvatarAlt', [title])} src={authorAvatarPath} />
|
||||
<Avatar
|
||||
avatarPath={authorAvatarPath}
|
||||
color={conversationColor}
|
||||
conversationType="direct"
|
||||
i18n={i18n}
|
||||
name={authorName}
|
||||
phoneNumber={authorPhoneNumber}
|
||||
profileName={authorProfileName}
|
||||
size={36}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import classNames from 'classnames';
|
||||
import moment from 'moment';
|
||||
|
||||
import { Avatar } from '../Avatar';
|
||||
import { ContactName } from './ContactName';
|
||||
import { Message, Props as MessageProps } from './Message';
|
||||
import { Localizer } from '../../types/Util';
|
||||
|
@ -31,40 +32,21 @@ interface Props {
|
|||
i18n: Localizer;
|
||||
}
|
||||
|
||||
function getInitial(name: string): string {
|
||||
return name.trim()[0] || '#';
|
||||
}
|
||||
|
||||
export class MessageDetail extends React.Component<Props> {
|
||||
public renderAvatar(contact: Contact) {
|
||||
const { i18n } = this.props;
|
||||
const { avatarPath, color, phoneNumber, name, profileName } = contact;
|
||||
|
||||
if (!avatarPath) {
|
||||
const initial = getInitial(name || '');
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'module-message-detail__contact__avatar',
|
||||
'module-message-detail__contact__default-avatar',
|
||||
`module-message-detail__contact__default-avatar--${color}`
|
||||
)}
|
||||
>
|
||||
{initial}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const title = `${name || phoneNumber}${
|
||||
!name && profileName ? ` ~${profileName}` : ''
|
||||
}`;
|
||||
|
||||
return (
|
||||
<img
|
||||
className="module-message-detail__contact__avatar"
|
||||
alt={i18n('contactAvatarAlt', [title])}
|
||||
src={avatarPath}
|
||||
<Avatar
|
||||
avatarPath={avatarPath}
|
||||
color={color}
|
||||
conversationType="direct"
|
||||
i18n={i18n}
|
||||
name={name}
|
||||
phoneNumber={phoneNumber}
|
||||
profileName={profileName}
|
||||
size={48}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* Corresponds to the theme setting in the app, and the class added to the root element.
|
||||
*/
|
||||
theme: 'light-theme' | 'dark-theme';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the parent elements necessary to allow the main Signal Desktop stylesheet to
|
||||
* apply (with no changes) to messages in the Style Guide.
|
||||
*/
|
||||
export class LeftPaneContext extends React.Component<Props> {
|
||||
public render() {
|
||||
const { theme } = this.props;
|
||||
|
||||
return (
|
||||
<div className={classNames(theme || 'light-theme')}>
|
||||
<div className="gutter">{this.props.children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import classNames from 'classnames';
|
|||
|
||||
import { default as _ } from 'lodash';
|
||||
export { ConversationContext } from './ConversationContext';
|
||||
export { LeftPaneContext } from './LeftPaneContext';
|
||||
|
||||
export { _, classNames };
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const BAD_CHARACTERS = /[^A-Za-z\s]+/g;
|
||||
const WHITESPACE = /\s+/g;
|
||||
|
||||
function removeNonInitials(name: string) {
|
||||
return name.replace(BAD_CHARACTERS, '').replace(WHITESPACE, ' ');
|
||||
}
|
||||
|
||||
export function getInitials(name?: string): string | null {
|
||||
if (!name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cleaned = removeNonInitials(name);
|
||||
const parts = cleaned.split(' ');
|
||||
const initials = parts.map(part => part.trim()[0]);
|
||||
if (!initials.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return initials.slice(0, 2).join('');
|
||||
}
|
Loading…
Reference in New Issue