element and the ::before content
can sit there. `auto` will take on
the height and width otherwise assigned
to the .message_inline_image. Setting
the min value to 0 on minmax() ensures
that media larger than those dimensions
don't cause a grid blowout. */
grid-template: "media" minmax(0, auto) / minmax(0, auto);
}
p:first-child > .katex-display > .katex,
.message_inline_image .media-anchor-element,
.message_inline_image .media-video-element {
/* We explicitly place the containing
media element in the thumbnail area. */
grid-area: media;
}
p:first-child > .katex-display::before,
.message_inline_image::before {
/* We generate a single . here to create
text content enough for a baseline.
Generated content is not generally
read aloud to screen readers. */
content: ".";
/* We color the generated . transparently,
so it won't be visible when the media
doesn't cover the entire area. */
color: transparent;
/* And we explicitly place the . in the thumbnail
area, too. Otherwise, grid would generate a new
column track for it to sit in. */
grid-area: media;
}
}
.twitter-tweet {
border: 1px solid hsl(0deg 0% 87%);
padding: 0.5em 0.75em;
margin-bottom: 0.25em;
overflow-wrap: anywhere;
min-height: 48px;
}
.twitter-avatar {
float: left;
width: 48px;
height: 48px;
margin-right: 0.75em;
}
.message_inline_ref {
margin-bottom: var(--markdown-interelement-space-px);
margin-left: 5px;
height: 50px;
display: block !important;
border: none !important;
}
&.rtl .message_inline_ref {
margin-left: unset;
margin-right: 5px;
}
.message_inline_image .media-image-element {
cursor: zoom-in;
}
.youtube-video .media-image-element,
.vimeo-video .media-image-element,
.embed-video .media-image-element {
cursor: pointer;
}
.youtube-video .media-image-element {
/* We do this for the sake of increasing
the size of older YouTube thumbnail
previews, but there are no ill effects
on newer preview images. */
object-fit: contain;
}
.message_inline_video,
.message_inline_animated_image_still,
.youtube-video .media-anchor-element {
/* Once collections of thumbnails are set to render as
flex items, this can be updated to use `display: grid`
instead of `display: inline-grid`. */
display: inline-grid;
grid-template: "media" minmax(0, auto) / minmax(0, auto);
place-items: center center;
&:hover {
&::after {
transform: scale(1);
}
}
/* The .media-anchor-selector is for all media
except YouTube, which needs to place
.media-image-element on the grid. */
& .media-anchor-element,
& .media-image-element {
grid-area: media;
}
&::after {
grid-area: media;
content: "";
background-image: url("../images/play_button.svg");
background-position: center center;
background-repeat: no-repeat;
/* 32px at 14px/1em */
background-size: 2.2857em;
/* Match the box to the play button's
background-size value. */
width: 2.2857em;
height: 2.2857em;
border-radius: 100%;
transform: scale(0.8);
transition: transform 0.2s;
}
& .media-video-element {
display: block;
object-fit: contain;
/* Since we do not yet read height and width
values for media thumbnails, we carry forward
reasonable dimensions for a landscape thumbnail
here. */
height: 8em;
width: 12em;
}
}
.youtube-video .media-anchor-element {
/* We display the youtube-video anchor
as a grid, not inline grid, to avoid
additional space beneath the thumbnail. */
display: grid;
}
.message_embed {
display: grid;
grid-template-columns:
[thumbnail-start] var(--length-message-preview-embeds)
[thumbnail-end fader-start data-container-start] minmax(0, 1fr)
[data-container-end fader-end];
grid-template-rows:
[border-start thumbnail-start data-container-start] calc(
var(--length-message-preview-embeds) - 10%
)
[fader-start] 10% [data-container-end thumbnail-end border-end fader-end];
column-gap: 5px;
margin: 0 0 var(--markdown-interelement-space-px);
/* We want to control the height without worrying about
padding... */
box-sizing: border-box;
/* ...though we will account for 10px of padding in the
height itself, so that the fade effect on long description
text works as expected. */
height: calc(var(--length-message-preview-embeds) + 10px);
padding: 5px;
border-left: 3px solid hsl(0deg 0% 93%);
.message_embed_title {
font-size: 1.2em;
/* 5px at 16.8px (1.2 * 14px) */
margin-top: -0.2976em;
/* We set the markdown link colors here so
that the ellipsis takes it on truncated
lines. The ellipsis will not take an
underline even if we specify one, so
that is deliberately omitted here. */
color: var(--color-markdown-link);
&:hover {
color: var(--color-markdown-link-hover);
}
.message-embed-title-link {
/* Line-clamp lines seem to have a small
interline area that's not clickable
unless we set the anchor to display as
a block. */
display: block;
}
}
.message_embed_title,
.message_embed_description {
/* Clamp multi-line titles and descriptions
to two lines. */
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
/* Break overflowing words as necessary. */
overflow-wrap: break-word;
}
.message_embed_image {
display: block;
grid-area: thumbnail;
/* Keep the embed image square. */
max-height: var(--length-message-preview-embeds);
background-size: cover;
background-position: center;
}
.data-container {
grid-area: data-container;
overflow: hidden;
}
}
/* Although grid will automatically respond to
RTL languages, we still need to manually fix
the border here, which is not part of grid. */
&.rtl .message_embed {
border-left: unset;
border-right: 3px solid hsl(0deg 0% 93%);
}
& a {
color: var(--color-markdown-link);
text-decoration: none;
& code {
color: var(--color-markdown-code-link);
}
&:hover,
&:focus {
color: var(--color-markdown-link-hover);
text-decoration: underline;
& code {
color: var(--color-markdown-code-link-hover);
}
}
}
& pre {
direction: ltr;
/* code block text is a bit smaller than normal text */
font-size: 0.825em;
line-height: 1.4;
white-space: pre;
overflow-x: auto;
word-break: break-all;
word-wrap: normal;
margin: 0 0 var(--markdown-interelement-space-px);
padding: 5px 7px 3px;
display: block;
border-radius: 4px;
&:hover .code-buttons-container {
visibility: visible;
}
/* Hide the code buttons container when the user is
clicking on the code block other than the buttons.
This allows the user to select part of the the code
without the buttons interfering with the selection. */
&:active .code-buttons-container:not(:hover) {
visibility: hidden;
}
}
& pre code {
font-size: inherit;
padding: 0;
white-space: inherit;
overflow-x: scroll;
/* Unset to avoid compounding alpha values */
background-color: unset;
color: inherit;
border: 0;
}
& code {
/* 11.55px when body is the default 14px; this is chosen to be
slightly above the 11.5px threshold where the height jumps by a
pixel on most platforms. */
font-size: 0.825em;
unicode-bidi: embed;
direction: ltr;
white-space: pre-wrap;
/* 1px at 14px/1em */
padding: 0.0714em 2px;
color: var(--color-markdown-code-text);
background-color: var(--color-markdown-code-background);
border-radius: 3px;
}
/* Container for buttons inside code blocks. */
.code-buttons-container {
/* Break white-space treatment inherited from */
white-space: collapse;
/* Present buttons in a flexbox layout. */
display: flex;
align-items: center;
gap: 3px;
/* Having absolute positioning here ensures that the element
doesn't scroll along with the code div in narrow windows */
position: absolute;
top: 4px;
right: 0;
padding: 0 4px;
/* Invisible unless is hovered. */
visibility: hidden;
z-index: 0;
}
/* The properties of the code_external_link button are copied from the
copy-button class in app_components.css. */
.code_external_link {
display: flex;
border-radius: 4px;
color: var(--color-copy-button);
/* 2px at 16px/1em */
padding: 0.125em;
cursor: pointer;
&:hover,
:focus-visible {
background-color: var(--color-copy-button-square-bg-hover);
}
&:active {
background-color: var(--color-copy-button-square-bg-active);
color: var(--color-copy-button-square-active);
}
}
.copy_codeblock,
.code_external_link {
font-size: 1.1363em;
border: 1px solid var(--color-copy-button-square-bg-active);
backdrop-filter: blur(20px);
}
}
.group_mention,
.direct_mention {
& .rendered_markdown pre {
background-color: var(--color-markdown-pre-background-mentions);
border-color: var(--color-markdown-pre-border-mentions);
}
& .rendered_markdown code {
background-color: var(--color-markdown-code-background-mentions);
}
& .rendered_markdown pre code {
background-color: unset;
border-color: unset;
}
}
.preview_content .copy_codeblock {
/* We avoid displaying copy_codeblock button in previews, because it
feels odd given that you can just copy-paste the code out of
the "edit" state. We may change this decision when we add
menu options for viewing the code in a coding playground. */
display: none;
}
.informational-overlays .copy_codeblock {
display: none;
}
.message_edit_history_content .copy_codeblock {
/* Copy code block button is hidden in edit history, this is done
because of issues faced in copying code blocks in edit history
modal. This may be changed later as we decide upon a proper ux
for displaying edit-history. */
display: none;
}
.message_edit_history_content .code_external_link {
right: 5px;
}
.preview_content .code_external_link {
right: 12px;
}
@media (width < $sm_min) {
.rendered_markdown .message_embed {
height: auto;
.message_embed_image {
width: 100%;
height: 100px;
}
.data-container {
display: block;
max-width: 100%;
margin-top: 10px;
}
}
}
.codehilite {
display: block !important;
border: none !important;
background: none !important;
/* Set a relative positioning context to more precisely
position .code-buttons-container. This eliminates
problems with positioning shifts associated with
code blocks in spoilers, too. */
position: relative;
& pre {
color: var(--color-markdown-pre-text);
/* This is necessary to remove the background color
set by Pygments. */
background-color: var(--color-markdown-pre-background);
border: 1px solid var(--color-markdown-pre-border);
}
}
/* Both the horizontal scrollbar in as well as
vertical scrollbar in the is styled similarly. */
.message_edit_form textarea,
.rendered_markdown pre {
/* Ensure the horizontal scrollbar is visible on Mac */
&::-webkit-scrollbar {
height: 8px;
width: 10px;
background-color: hsl(0deg 0% 0% / 5%);
}
&::-webkit-scrollbar-thumb {
background-color: hsl(0deg 0% 0% / 30%);
border-radius: 20px;
cursor: auto;
transition: background-color 0.2s ease;
}
&::-webkit-scrollbar-thumb:hover {
background-color: hsl(0deg 0% 0% / 60%);
}
}
/* Search highlight used in both topics and rendered_markdown */
.highlight {
background-color: hsl(51deg 100% 79%);
}
/* For elements where we want to show as much markdown content we can
in a single line and then hide the overflowing part. */
.single-line-rendered-markdown {
/* Any element which can `wrap` in the above defined elements. */
code,
.stream-topic {
white-space: nowrap;
}
}
.user-mention {
i.zulip-icon-bot {
vertical-align: middle;
position: relative;
top: -1px;
padding-left: 0.3em;
}
}