signal-desktop/stylesheets/_conversation.scss
Scott Nonnenberg c02860af5c
Responding to pull request review feedback
- messages.getQuoteObjectUrl: early return
- backup.js: explaining variables for long if statement
- types/messages.js: Log if thumbnail has neither data nor path
- sendmessage.js:
  - remove extraneous logging
  - fix indentation
  - upload attachments and thumbnails in parallel
- preload: don't load fs for tests, just fse
- _conversation.scss: split two selectors into two lines, 0px -> 0
- backup_test.js: use fse.existsSync and comment twoSlashes regex
- network_tests_view_test.js: Comment duplicate assignment to window.getSocketStatus
2018-04-23 15:36:47 -07:00

1146 lines
20 KiB
SCSS

.conversation-title {
display: block;
line-height: 36px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 0 46px;
-webkit-user-select: text;
}
.conversation-name + .conversation-number {
&:before {
content:"\00b7"; // &middot
font-weight: bold;
padding: 0 5px 0 4px;
}
}
.conversation-title .verified {
&:before {
content:"\00b7"; // &middot
font-weight: bold;
padding: 0 5px 0 4px;
}
}
.conversation-title .verified-icon {
@include color-svg('../images/verified-check.svg', white);
display: inline-block;
width: 1.25em;
height: 1.25em;
vertical-align: text-bottom;
}
.conversation {
background-color: white;
height: 100%;
position: relative;
.conversation-loading-screen {
z-index: 99;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: #eee;
display: flex;
align-items: center;
.content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.container {
position: absolute;
left: 50%;
width: 78px;
transform: translate(-50%, 0);
}
.dot {
width: 14px;
height: 14px;
border: 3px solid $blue;
border-radius: 50%;
float: left;
margin: 0 6px;
transform: scale(0);
animation: loading 1500ms ease infinite 0ms;
&:nth-child(2) {
animation: loading 1500ms ease infinite 333ms;
}
&:nth-child(3) {
animation: loading 1500ms ease infinite 666ms;
}
}
}
.panel {
height: calc(100% - #{$header-height});
overflow-y: scroll;
.container {
padding-top: 20px;
max-width: 750px;
margin: 0 auto;
padding: 20px;
}
}
.main.panel {
display: flex;
flex-direction: column;
overflow: initial;
.discussion-container {
flex-grow: 1;
position: relative;
max-width: 100%;
margin: 0;
.bar-container {
height: 5px;
}
.message-list {
position: absolute;
top: 0;
height: 100%;
width: 100%;
margin: 0;
padding: 10px 0 0 0;
overflow-y: auto;
}
}
}
}
.discussion-container {
background-color: #eee;
}
.key-verification {
label {
display: block;
margin: 10px 0;
font-size: $font-size-small;
}
.icon {
height: 1.25em;
width: 1.25em;
vertical-align: text-bottom;
display: inline-block;
&.verified {
@include color-svg('../images/verified-check.svg', $grey_d);
}
&.shield {
@include color-svg('../images/shield.svg', $grey_d);
}
}
.key, .placeholder {
padding: 0 1em;
-webkit-user-select: text;
}
.key {
font-family: monospace;
padding: 10px;
margin: 20px auto 20px auto;
width: 16em;
background: $grey_l;
border: solid 1px $grey_l2;
border-radius: $border-radius;
}
.placeholder {
font-weight: bold;
}
.qr {
border-radius: 200px;
border: solid 1px $grey_l2;
width: 150px;
height: 150px;
text-align: center;
padding: 25px;
margin: 10px auto;
canvas {
display: none;
}
img {
display: inline-block;
max-width: 100%;
}
}
.summary {
margin: 30px 0 10px;
text-align: center;
}
div.verify {
text-align: center;
}
button.verify {
border-radius: 5px;
font-weight: bold;
padding: 10px;
margin: 0;
}
}
.identity-key-send-error {
button {
margin-top: 0px;
margin-bottom: 0px;
}
.explanation {
margin-top: 20px;
}
.safety-number {
margin-top: 30px;
text-align: center;
}
.actions {
margin-top: 30px;
text-align: center;
}
}
.message-detail {
background-color: #eee;
.message-container {
padding: 20px 0;
.sender {
display: none;
}
}
.info {
padding: 1em;
.label {
font-weight: bold;
padding-right: 1em;
vertical-align: top;
}
button {
border: none;
border-radius: $border-radius;
color: white;
padding: 0.5em;
font-weight: bold;
span {
vertical-align: middle;
}
}
}
.retries {
padding: 1em;
}
button.retry {
margin: 0.5em;
}
.contacts .contact-detail {
padding: 0 36px;
margin-bottom: 5px;
.status-icon-container,
.error-icon-container {
float: right;
}
button.error {
background-color: red;
color: white;
span.icon.error {
display: inline-block;
width: 1.25em;
height: 1.25em;
position: relative;
vertical-align: middle;
@include color-svg('../images/warning.svg', white);
}
}
.error-message {
margin: 6px 0 0;
font-size: $font-size-small;
font-weight: bold;
color: red;
}
}
h3 {
font-size: 1em;
padding: 5px;
}
button.cancel {
float: right;
color: $grey_d;
border: solid 1px #ccc;
}
.delete-container {
text-align: center;
button.delete {
background-color: red;
color: white;
}
}
}
.message-list {
.error-icon {
cursor: pointer;
}
.advisory {
text-align: center;
.content {
display: inline-block;
padding: 5px 10px;
background: #fff5c4;
border-radius: $border-radius;
}
}
}
li.entry .error-icon-container {
position: absolute;
top: 0;
left: calc(100% + 5px);
height: 100%;
.error-icon {
display: block;
height: 100%;
}
.error-message {
display: none;
position: absolute;
background: black;
color: white;
border-radius: $border-radius;
padding: 0.5em;
font-weight: normal;
bottom: calc(50% + 18px);
left: -84px;
width: 180px;
z-index: 10;
&:before {
display: block;
content: '';
position: absolute;
bottom: -16px;
left: 50%;
border: 6px solid transparent;
border-top: 10px solid #000000;
}
}
&:hover .error-message { display: inline-block; }
}
li.entry .menu-container {
position: absolute;
top: 0;
left: calc(100% + 5px);
height: 100%;
display: flex;
align-items: center;
justify-content: center;
.menu-anchor {
position: relative;
}
li {
margin: 0px;
}
cursor: pointer;
}
.dots-horizontal-icon {
visibility: hidden;
}
li.entry:hover .dots-horizontal-icon {
visibility: visible;
}
li.entry.outgoing .menu-container {
left: auto;
right: calc(100% + 5px);
}
.incoming .menu-list {
left: 0;
right: auto;
}
.error-icon {
display: inline-block;
width: $error-icon-size;
height: $error-icon-size;
position: relative;
@include color-svg('../images/warning.svg', red);
}
.dots-horizontal-icon {
display: inline-block;
width: $error-icon-size;
height: $error-icon-size;
position: relative;
@include color-svg('../images/dots-horizontal.svg', gray);
&:hover {
@include color-svg('../images/dots-horizontal.svg', black);
}
}
.group {
li.entry .unregistered-user-error {
display: none;
}
}
.group-update {
font-size: smaller;
}
.private .entry .avatar,
.private .sender,
.outgoing .sender {
display: none;
}
.sender {
font-size: smaller;
opacity: 0.8;
margin-bottom: 5px;
font-weight: bold;
}
.timestamp {
margin-right: 3px;
white-space: nowrap;
}
// There's a p.status used in the onboarding screen, so this needs to be more specific
span.status {
width: 18px;
height: 18px;
}
.sent span.status {
display: inline-block;
@include color-svg('../images/check.svg', black);
}
.delivered span.status {
display: inline-block;
@include color-svg('../images/double-check.svg', black);
}
.read span.status {
display: inline-block;
@include color-svg('../images/double-check.svg', $blue);
}
.pending span.status {
display: inline-block;
background: none;
&:before { content: '...'; }
}
.message-container,
.message-list {
list-style: none;
li {
max-width: 800px;
margin: 0 auto 10px;
padding-left: 1em;
// we need more padding on right side because scroll bar overlaps
padding-right: 1.5em;
&::after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
}
.bubble {
position: relative;
left: -2px;
display: inline-block;
vertical-align: top;
word-wrap: break-word;
margin-left: 8px;
max-width: 30em;
text-align: -webkit-auto;
-webkit-user-select: text;
@media(max-width: 825px) {
max-width: calc(100% - 45px - #{$error-icon-size}); // avatar size + padding + error-icon size
}
.body {
white-space: pre-wrap;
a {
word-break: break-all
}
}
.attachments + .content {
margin-top: 0.5em;
}
.quote-wrapper + .content {
margin-top: 0.5em;
}
p {
margin: 0;
}
}
.meta {
font-size: smaller;
margin-top: 3px;
text-align: right;
line-height: 18px;
.hasRetry + .timestamp {
&:before {
content:"\00b7"; // &middot
font-weight: bold;
padding: 0 5px 0 4px;
text-decoration: none;
opacity: 0.5;
}
}
.retry {
text-decoration: underline;
cursor: pointer;
}
.some-failed {
float: left;
margin-left: 6px;
margin-right: 6px;
cursor: pointer;
}
.hasRetry, .timestamp, .status, .timer {
float: left;
}
.timestamp, .status {
cursor: pointer;
opacity: 0.5;
&:hover {
opacity: 1.0;
}
}
}
.incoming {
.avatar, .bubble {
float: left;
}
}
.outgoing {
.meta {
float: right;
}
.error-icon-container {
left: auto;
right: calc(100% + 5px);
}
.avatar, .bubble {
float: right;
}
.bubble {
clear: left;
}
}
@keyframes shake {
0% { transform: translateX(0px); }
25% { transform: translateX(-5px); }
50% { transform: translateX(0px); }
75% { transform: translateX(5px); }
100% { transform: translateX(0px); }
}
.expired .bubble {
animation: shake 0.2s linear 3;
}
.timer {
display: none;
.hourglass {
vertical-align: middle;
}
}
.control {
.bubble {
.content {
font-style: italic;
}
&::before, &::after {
display: none;
}
}
}
.attachments {
a {
font-style: italic;
display: block;
padding: 1em;
background-color: #ccc;
}
img, audio, video {
display: block;
max-width: 100%;
max-height: 300px;
}
video {
background: black;
min-height: 300px;
min-width: 280px;
}
img {
cursor: pointer;
}
.fileView {
display: flex;
align-items: center;
overflow: hidden;
position: relative;
padding: 5px;
padding-right: 10px;
padding-bottom: 0px;
cursor: pointer;
.fileName {
font-weight: bold;
margin-bottom: 0.25em;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.text {
overflow: hidden;
}
.icon, .text {
opacity: 0.75;
}
&:hover {
.icon, .text {
opacity: 1.0;
}
}
.icon {
margin-left: -0.5em;
margin-right: 0.5em;
display: inline-block;
vertical-align: middle;
width: $button-height * 2;
height: $button-height * 2;
@include color-svg('../images/file.svg', $grey_d);
&.audio {
@include color-svg('../images/audio.svg', $grey_d);
}
&.video {
@include color-svg('../images/video.svg', $grey_d);
}
&.voice {
@include color-svg('../images/voice.svg', $grey_d);
}
}
}
}
.outgoing .avatar {
display: none;
}
.bubble .content.error-message {
cursor: pointer;
font-style: italic;
}
}
.quoted-message {
@include message-replies-colors;
@include twenty-percent-colors;
&.no-click {
cursor: auto;
}
position: relative;
cursor: pointer;
display: flex;
flex-direction: row;
align-items: stretch;
overflow: hidden;
border-radius: 2px;
background-color: #eee;
position: relative;
margin-right: $android-bubble-quote-padding - $android-bubble-padding-horizontal;
margin-left: $android-bubble-quote-padding - $android-bubble-padding-horizontal;
margin-bottom: 0.5em;
// Accent color border:
border-left-width: 3px;
border-left-style: solid;
.primary {
flex-grow: 1;
padding-left: 10px;
padding-right: 10px;
padding-top: 6px;
padding-bottom: 6px;
// Will turn on in the iOS theme. This extra element is necessary because the iOS
// theme requires text that isn't used at all in the Android Theme
.ios-label {
display: none;
}
.author {
font-weight: bold;
margin-bottom: 0.3em;
@include text-colors;
.profile-name {
font-size: smaller;
}
}
.text {
white-space: pre-wrap;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
// Note: -webkit-line-clamp doesn't work for RTL text, and it forces you to use
// ... as the truncation indicator. That's not a solution that works well for
// all languages. More resources:
// - http://hackingui.com/front-end/a-pure-css-solution-for-multiline-text-truncation/
// - https://medium.com/mofed/css-line-clamp-the-good-the-bad-and-the-straight-up-broken-865413f16e5
}
.type-label {
font-style: italic;
font-size: 12px;
}
.filename-label {
font-size: 12px;
}
}
.close-container {
position: absolute;
top: 4px;
right: 4px;
height: 16px;
width: 16px;
background-color: rgba(255, 255, 255, 0.75);
border-radius: 50%;
.close-button {
width: 100%;
height: 100%;
@include color-svg('../images/x.svg', $grey);
}
}
.icon-container {
flex: initial;
min-width: 50px;
width: 50px;
height: 50px;
position: relative;
.circle-background {
position: absolute;
left: 6px;
right: 6px;
top: 6px;
bottom: 6px;
border-radius: 50%;
@include avatar-colors;
&.white {
background-color: white;
}
}
.icon {
position: absolute;
left: 12px;
right: 12px;
top: 12px;
bottom: 12px;
&.file {
@include color-svg('../images/file.svg', white);
}
&.image {
@include color-svg('../images/image.svg', white);
}
&.microphone {
@include color-svg('../images/microphone.svg', white);
}
&.play {
@include color-svg('../images/play.svg', white);
}
&.movie {
@include color-svg('../images/movie.svg', white);
}
@include avatar-colors;
}
.inner {
position: relative;
height: 50px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
object-fit: cover;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
}
}
// We only add margin if there's no 'sender' element beforehand, which is only possible
// on incoming messages, and only in groups (when we're not in a .private conversation).
.outgoing .quoted-message,
.private .incoming .quoted-message {
margin-top: $android-bubble-quote-padding - $android-bubble-padding-vertical;
}
.bottom-bar .quoted-message {
margin: 0;
}
// We need to use the wrapper because the conversation view calculates the height of all
// things in the composition area. A margin on an inner div won't be included in that
// height calculation.
.bottom-bar .quote-wrapper {
margin-right: 5px;
margin-bottom: 5px;
}
.send .quote-wrapper {
margin-left: 46px;
margin-top: 5px;
margin-right: 75px;
margin-bottom: 0px;
}
.incoming .quoted-message {
background-color: rgba(white, 0.6);
border-top: none;
border-bottom: none;
border-right: none;
border-left-color: white;
}
.message-list,
.message-container {
.avatar {
height: 36px;
width: 36px;
line-height: 36px;
}
}
.bottom-bar {
box-sizing: content-box;
$button-width: 36px;
padding: 5px 0px 5px 0;
background: $grey_l;
.compose {
padding-right: 5px;
}
form.active {
outline: solid 1px $blue;
}
form.send {
background: #ffffff;
}
input, textarea {
color: $grey_d;
}
.attachment-previews {
padding: 0 36px;
.attachment-preview {
padding: 13px 10px 0;
}
img {
border: 2px solid #ddd;
border-radius: $border-radius;
max-height: 100px;
}
.close {
position: absolute;
top: 5px;
right: 2px;
background: #999;
&:hover {
background: $grey;
}
}
}
.flex {
display: flex;
flex-direction: row;
.send-message {
flex-grow: 1;
}
}
.choose-file {
float: left;
height: 36px;
}
.send-message {
display: block;
max-height: 100px;
padding: 10px;
margin: 0 5px;
border: 0;
outline: 0;
z-index: 5;
resize: none;
font-size: 1em;
font-family: inherit;
&[disabled=disabled] {
background: transparent;
}
}
.capture-audio {
float: right;
height: 36px;
}
.android-length-warning {
padding: 10px;
max-width:150px;
}
}
.toast {
position: absolute;
bottom: 0;
margin: 0 2em 3em;
padding: 0.5em 1.5em;
background: rgba(0, 0, 0, 0.75);
color: white;
box-shadow: 0 0 5px 0 black;
border-radius: $border-radius;
font-size: $font-size-small;
z-index: 100;
}
.confirmation-dialog {
.content {
max-width: 350px;
margin: 100px auto;
padding: 1em;
background: white;
border-radius: $border-radius;
overflow: auto;
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, 0.3);
.buttons {
margin-top: 10px;
button {
float: right;
margin-left: 10px;
background-color: $grey_l;
border-radius: $border-radius;
padding: 5px 8px;
border: 1px solid $grey_l2;
&:hover {
background-color: $grey_l2;
border-color: $grey_l3;
}
}
}
}
}
.advisory .icon {
height: 1.25em;
width: 1.25em;
vertical-align: text-bottom;
display: inline-block;
&.verified {
@include color-svg('../images/verified-check.svg', $grey_d);
}
&.shield {
@include color-svg('../images/shield.svg', $grey_d);
}
&.clock {
@include color-svg('../images/clock.svg', $grey_d);
}
}
.keychange {
text-align: center;
.content {
cursor: pointer;
display: inline-block;
padding: 5px 10px;
background: #fff5c4;
border-radius: $border-radius;
}
}
.verified-change {
text-align: center;
.content {
cursor: pointer;
display: inline-block;
padding: 5px 10px;
background: #fff5c4;
border-radius: $border-radius;
}
}
.message-list .last-seen-indicator-view {
// This padding is large so we clear the avatar circle extending into the conversation
// window.scrollIntoView() doesn't honor margins, so we're using padding
// padding-top is less to account for the 10px margin at the bottom of messages
padding-top: 25px;
padding-bottom: 35px;
.bar {
display: flex;
flex-direction: column;
align-items: center;
padding: 5px;
border-top: 1px solid rgba(255, 255, 255, 0.15);
border-bottom: 1px solid rgba(0, 0, 0, 0.055);
background-color: rgba(0, 0, 0, 0.05);
}
.text {
font-size: 12px;
text-transform: uppercase;
letter-spacing: .06em;
background-color: white;
border-radius: 1.5em;
padding: 10px 21px 9px 21px;
}
}
.discussion-container .scroll-down-button-view {
position: absolute;
right: 20px;
bottom: 10px;
button {
height: 44px;
width: 44px;
border-radius: 22px;
text-align: center;
background-color: white;
border: none;
box-shadow: 0px 3px 5px 0px rgba(0,0,0,0.2);
.icon {
@include color-svg('../images/down.svg', $grey_l3);
height: 100%;
width: 100%;
}
.icon:hover {
background-color: #616161;
}
&.new-messages {
background-color: $blue;
.icon {
@include color-svg('../images/down.svg', white);
}
&:hover {
background-color: #1472bd;
}
}
}
}