mirror of
https://github.com/zulip/zulip.git
synced 2026-06-30 21:11:04 +08:00
This corrects for an issue where hover controls would remain visible after multiple clicks on one of the hover control icons, despite the mouse pointer leaving the area. This does not really create a regression for keyboard focus, as there is currently no reasonable way to get a Tab key into the hover controls area. However, if one clicks multiple times on the vdots icon, and uses Tab to move back and forth, the icons still remain visible--thanks to the mouse pointer still being in the hover area.
479 lines
16 KiB
CSS
479 lines
16 KiB
CSS
$avatar_column_width: 46px;
|
|
$distance_of_text_elements_from_message_box_top: 8.5px;
|
|
$distance_of_non_text_elements_from_message_box: 6px;
|
|
$message_box_margin: 3px;
|
|
|
|
/* The time column usually just needs enough space to display the
|
|
timestamp. The minimum width here is enough for "22:22 PM", which
|
|
is roughly the widest this will be in English; this is nice as the
|
|
timestamps and message controls will be vertically aligned.
|
|
|
|
But in some locales, the time encoding is wider, (especially where
|
|
the "PM" abbreviation is longer), so we allow the column to be
|
|
wider for individual messages if required, up to `max-content`, to
|
|
prevent ugly line-wrapping. In practice, it's unlikely we'll see
|
|
anything wider than 60px. */
|
|
$time_column_min_width: 42px; /* + padding */
|
|
|
|
.message_row {
|
|
display: grid;
|
|
grid-template: auto auto / 2px 1fr;
|
|
grid-template-areas:
|
|
"date_unread_marker date_row "
|
|
"message_unread_marker messagebox";
|
|
|
|
border-left: 1px solid var(--color-message-list-border);
|
|
border-right: 1px solid var(--color-message-list-border);
|
|
background-color: var(--color-background-stream-message-content);
|
|
|
|
&.direct_mention {
|
|
background-color: var(--color-background-direct-mention);
|
|
}
|
|
|
|
&.group_mention {
|
|
background-color: var(--color-background-group-mention);
|
|
}
|
|
|
|
.date_row {
|
|
grid-area: date_row;
|
|
/* We only want padding for the date rows between recipient blocks */
|
|
padding-bottom: 0;
|
|
|
|
& span {
|
|
font-size: calc(12em / 14);
|
|
font-style: normal;
|
|
font-weight: 600;
|
|
line-height: 17px; /* identical to box height, or 131% */
|
|
text-align: right;
|
|
letter-spacing: 0.04em;
|
|
color: var(--color-date);
|
|
/* Right padding matches time in message row and date in recipient row. */
|
|
padding: 8px 6px 8px 4px;
|
|
}
|
|
}
|
|
|
|
.unread_marker {
|
|
margin-left: var(--unread-marker-left);
|
|
opacity: 0;
|
|
transition: all 0.3s ease-out;
|
|
|
|
&.slow_fade {
|
|
transition: all 2s ease-out;
|
|
}
|
|
|
|
&.fast_fade {
|
|
transition: all 0.3s ease-out;
|
|
}
|
|
|
|
&.date_unread_marker {
|
|
grid-area: date_unread_marker;
|
|
|
|
.unread-marker-fill {
|
|
border-radius: 0 !important;
|
|
height: 100% !important;
|
|
}
|
|
}
|
|
|
|
&.message_unread_marker {
|
|
grid-area: message_unread_marker;
|
|
}
|
|
}
|
|
|
|
.unread-marker-fill {
|
|
height: 100%;
|
|
width: 2px;
|
|
background: linear-gradient(
|
|
90deg,
|
|
var(--color-unread-marker) 30%,
|
|
hsl(217deg 64% 59% / 0%)
|
|
);
|
|
}
|
|
|
|
&.unread .unread_marker {
|
|
transition: all 0.3s ease-out;
|
|
opacity: 1;
|
|
}
|
|
|
|
.messagebox {
|
|
grid-area: messagebox;
|
|
word-wrap: break-word;
|
|
cursor: pointer;
|
|
border: none;
|
|
/* The left padding value accounts for a 2px
|
|
unread marker, ensuring a uniform 5px of
|
|
padding on either side of the message box. */
|
|
padding: 0 5px 0 3px;
|
|
|
|
&:hover .message_controls,
|
|
&:hover .message_failed {
|
|
.empty-star:hover {
|
|
cursor: pointer;
|
|
}
|
|
|
|
> div {
|
|
opacity: 1;
|
|
visibility: visible;
|
|
}
|
|
}
|
|
}
|
|
|
|
.messagebox .messagebox-content {
|
|
display: grid;
|
|
align-items: baseline;
|
|
padding-left: 10px;
|
|
grid-template:
|
|
var(--message-box-icon-height) repeat(3, auto) /
|
|
$avatar_column_width auto calc(3 * var(--message-box-icon-width))
|
|
8px minmax($time_column_min_width, max-content);
|
|
/* Named grid areas provide flexibility for positioning grid items
|
|
reliably, even if the row or column definitions of the grid change. */
|
|
grid-template-areas:
|
|
"edited message controls . time"
|
|
". message . . . "
|
|
". more . . . "
|
|
". reactions . . . ";
|
|
|
|
@media (width < $sm_min), ((width >= $md_min) and (width < $mc_min)) {
|
|
grid-template-columns: $avatar_column_width auto max-content 8px minmax(
|
|
$time_column_min_width,
|
|
max-content
|
|
);
|
|
}
|
|
|
|
.message_controls {
|
|
grid-area: controls;
|
|
justify-self: end;
|
|
padding: 0;
|
|
|
|
@media (width < $sm_min),
|
|
((width >= $md_min) and (width < $mc_min)) {
|
|
padding: 0 4px;
|
|
|
|
/* This is intended to target the first message_controls child
|
|
when there are 3 displayed. 4 = 3 + hidden message_failed element. */
|
|
.message_control_button:nth-last-child(4) {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
.message_edit_notice {
|
|
grid-area: edited;
|
|
}
|
|
|
|
.message_time {
|
|
justify-self: end;
|
|
padding-right: 5px;
|
|
/* Maintain first-line baseline regardless of
|
|
what happens in the message-content area (e.g., a
|
|
collapsed message, or source/edit view). This
|
|
line-height also keeps EDITED/MOVED messages
|
|
in place, care of their baseline-group participation
|
|
within the grid.
|
|
|
|
That said, 28px is a bit of a magical number.
|
|
In theory, this should be 27px. That's the height
|
|
of a single-message row without a sender. (See the
|
|
calculations for the height of a single-line,
|
|
sender-less message row in the message box grid.)
|
|
But when shifting into collapsed or source views,
|
|
28px is necessary to maintain the vertical alignment
|
|
of the EDITED messages, hover controls, and
|
|
timestamp. It's possible that this is also due to a
|
|
a rounding error, given how --message-box-line-height
|
|
is expressed as a unitless decimal. */
|
|
line-height: 28px;
|
|
text-align: end;
|
|
grid-area: time;
|
|
|
|
&.notvisible {
|
|
/* This happens when message failed to send. We don't want to
|
|
display time but still want it to occupy space. */
|
|
width: 45px !important;
|
|
position: unset !important;
|
|
}
|
|
}
|
|
|
|
.slow-send-spinner {
|
|
display: none;
|
|
justify-self: end;
|
|
margin-right: 10px;
|
|
text-align: end;
|
|
grid-area: time;
|
|
}
|
|
|
|
.message_content {
|
|
grid-area: message;
|
|
/*
|
|
Space between two single line messages in a paragraph is 10px.
|
|
There is 3px margin above and below a message. So, having a 2px
|
|
padding above and below the message will make the space between
|
|
all single paragraphs the same.
|
|
*/
|
|
padding: 2px 0;
|
|
color: var(--color-text-message-default);
|
|
line-height: var(--message-box-line-height);
|
|
min-height: 17px;
|
|
display: block;
|
|
position: relative;
|
|
overflow: hidden;
|
|
|
|
&:empty {
|
|
display: none;
|
|
}
|
|
|
|
&.condensed {
|
|
max-height: 8.5em;
|
|
min-height: 0;
|
|
overflow: hidden;
|
|
mask-image: linear-gradient(
|
|
to top,
|
|
hsl(0deg 0% 100% / 0%) 0%,
|
|
hsl(0deg 0% 100%) 60px
|
|
);
|
|
mask-size: cover;
|
|
}
|
|
|
|
&.collapsed {
|
|
padding: 0;
|
|
max-height: 0;
|
|
min-height: 0;
|
|
overflow: hidden;
|
|
}
|
|
}
|
|
|
|
.message_reactions {
|
|
grid-area: reactions;
|
|
display: flex;
|
|
/* Allow reactions to wrap in mobile viewports */
|
|
flex-wrap: wrap;
|
|
/* Keep reactions aligned to start (top), so that the
|
|
margin on the reaction button doesn't appear to
|
|
stretch the reactions taller. */
|
|
align-items: flex-start;
|
|
/* Control reaction spacing with a gap */
|
|
gap: 4px;
|
|
}
|
|
|
|
.message_edit {
|
|
grid-area: message;
|
|
/* Align self to start, rather than baseline, so the baseline
|
|
is preserved from the message itself--keeping the time,
|
|
edit message, and controls at the same vertical alignment. */
|
|
align-self: start;
|
|
/* Keep previewed messages from overflowing the grid area
|
|
that .message_edit is assigned to. */
|
|
overflow: hidden;
|
|
margin-top: $distance_of_non_text_elements_from_message_box;
|
|
}
|
|
|
|
.message_length_controller {
|
|
grid-area: more;
|
|
}
|
|
|
|
.collapsed ~ .message_length_controller {
|
|
/* When content is collapsed, the length controller
|
|
should occupy the space ordinarily assigned to
|
|
the message. */
|
|
grid-area: message;
|
|
/* However, don't let the SHOW MORE button participate
|
|
in the baseline group. */
|
|
align-self: start;
|
|
|
|
.message_length_toggle {
|
|
/* Ensure that a collapsed message maintains the
|
|
same space around the toggle button as any other
|
|
message-row content. */
|
|
margin: 4px 0;
|
|
}
|
|
}
|
|
|
|
&.content_edit_mode .message_length_controller {
|
|
/* If entering edit mode on a collapsed message,
|
|
just hide the controller area. This preserves
|
|
the collapsed state of the message, which need
|
|
not be touched. We just need to hide the button.
|
|
This works for condensed messages, too. */
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
&.include-sender {
|
|
.messagebox .messagebox-content {
|
|
grid-template-areas:
|
|
"avatar sender controls . time"
|
|
"avatar message . . . "
|
|
". more . . . "
|
|
". reactions . . . ";
|
|
|
|
.message_edit {
|
|
/* No top margin when there's a sender row */
|
|
margin-top: 0;
|
|
}
|
|
|
|
&.is-me-message {
|
|
grid-template-areas:
|
|
"avatar sender controls . time"
|
|
"avatar sender . . . "
|
|
". more . . . "
|
|
". reactions . . . ";
|
|
|
|
.message-avatar {
|
|
/* Set the line-height to match the height of the avatar image
|
|
to center me-messages within the baseline group. */
|
|
line-height: var(--message-box-avatar-height);
|
|
align-self: baseline;
|
|
}
|
|
|
|
.message_sender {
|
|
/* Don't display message sender as flexbox for me-messages. */
|
|
display: block;
|
|
/* This preserves a consistent bottom spacing on the me-message
|
|
grid, which ordinarily benefits from the margin of <p>
|
|
elements in the markdown--which single-line me-messages do
|
|
not receive.
|
|
|
|
It also ensures a uniform space-relationship between the top: of the avatar and the top of the sender_name line.
|
|
|
|
However, this should all arguably be handled from the grid
|
|
container or the grid definition itself. */
|
|
margin: $message_box_margin 0;
|
|
|
|
/* Set the same line-height as on message content for
|
|
me-messages. */
|
|
line-height: var(--message-box-line-height);
|
|
|
|
/* Display message components inline, with wrapping white-space,
|
|
so the sender name and message display as a continuous line
|
|
of wrapping text. */
|
|
.sender_name {
|
|
white-space: normal;
|
|
display: inline;
|
|
}
|
|
}
|
|
|
|
&.content_edit_mode {
|
|
.message_sender {
|
|
/* Keep the me-message participating in the baseline */
|
|
visibility: hidden;
|
|
}
|
|
|
|
.message_edit {
|
|
/* Use the sender grid area for the me-message edit/view-source box */
|
|
grid-area: sender;
|
|
margin-top: $distance_of_non_text_elements_from_message_box;
|
|
}
|
|
}
|
|
}
|
|
|
|
.message-avatar {
|
|
grid-area: avatar;
|
|
/* The picture should not participate in the baseline group. */
|
|
align-self: start;
|
|
/* Because the avatar may be the tallest element in a
|
|
single-line me message, this margin preserves the
|
|
overall height of the message box. */
|
|
margin: $distance_of_non_text_elements_from_message_box 0;
|
|
}
|
|
|
|
.status-message {
|
|
font-weight: normal;
|
|
}
|
|
|
|
.message_content {
|
|
padding-top: 0;
|
|
grid-area: message;
|
|
}
|
|
|
|
.message_time {
|
|
grid-area: time;
|
|
/* Don't adjust the line-height for collapsed or
|
|
edited/source messages when there's a sender,
|
|
as the sender text is always visible. */
|
|
line-height: inherit;
|
|
}
|
|
|
|
.slow-send-spinner {
|
|
align-self: center;
|
|
position: unset;
|
|
margin-top: 1px;
|
|
}
|
|
|
|
.message_edit_notice {
|
|
/* When the edit notice is inline, as on edited me-messages,
|
|
the inline-block and accompanying vertical-align styles will
|
|
apply */
|
|
display: inline-block;
|
|
vertical-align: baseline;
|
|
/* A bit of margin here helps these not look associated with the name. */
|
|
margin-left: 4px;
|
|
}
|
|
|
|
.message_controls {
|
|
grid-area: controls;
|
|
}
|
|
|
|
.message_sender {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
grid-area: sender;
|
|
display: flex;
|
|
/* Ensure flexed sender info (name, status emoji, inline EDITED)
|
|
forms a baseline group, which will participate with the
|
|
message-box grid's baseline group, too. */
|
|
align-items: baseline;
|
|
|
|
margin-top: $message_box_margin;
|
|
|
|
.zulip-icon.zulip-icon-bot {
|
|
align-self: center;
|
|
padding: 0 0 0 5px;
|
|
}
|
|
|
|
.sender_name {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
/* It is important to use line-height `normal` here since user's name can
|
|
be in any language and `line-height: 1` doesn't work to accommodate text
|
|
from start and end vertically in all languages. */
|
|
line-height: normal;
|
|
outline: none;
|
|
align-self: baseline;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Locally echoed messages. */
|
|
&.locally-echoed .message_time {
|
|
opacity: 0;
|
|
/* Don't show pointer when message_time doesn't has a link. */
|
|
cursor: default;
|
|
}
|
|
|
|
/* Show the spinner only for messages that are still locally echoed. */
|
|
&.locally-echoed .slow-send-spinner {
|
|
display: unset !important;
|
|
cursor: default;
|
|
}
|
|
}
|
|
|
|
.recipient_row {
|
|
/* See https://stackoverflow.com/questions/2717480/css-selector-for-first-element-with-class/8539107#8539107
|
|
for details on how this works */
|
|
.message_row.unread {
|
|
.date_unread_marker {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* Select all but the first .message_row.unread,
|
|
and remove the properties set from the previous rule. */
|
|
.message_row.unread ~ .message_row.unread {
|
|
.date_unread_marker {
|
|
display: block;
|
|
}
|
|
}
|
|
}
|