zulip/web/styles/left_sidebar.css

1215 lines
28 KiB
CSS

/* The width of the empty space in the sidebar to separate
content from the edge of the window */
$far_left_gutter_size: 10px;
/* This represents the space in the sidebar reserved for symbols like
the #; labels like the the stream name go to the right of this. */
$left_col_size: 19px;
/* The full topic indentation includes 4px of indent in addition to
the above (and another 5px of padding not measured here) */
$topic_indent: calc($far_left_gutter_size + $left_col_size + 4px);
$topic_resolve_width: 13px;
/* Space between section in the left sidebar. */
$sections_vertical_gutter: 8px;
$bottom_scrolling_buffer: 25px;
/* space direct message / stream / topic names from unread counters
and @ mention indicators by 3px on the right */
$before_unread_count_padding: 3px;
.hashtag {
&:empty {
&::after {
content: "#";
line-height: 0;
font-size: 18px;
font-weight: 700;
}
}
}
#streams_list .stream-privacy {
height: 16px;
font-weight: 700;
text-align: center;
.zulip-icon.zulip-icon-globe {
font-size: 12px;
}
.zulip-icon.zulip-icon-hashtag {
font-size: 13px;
}
.zulip-icon.zulip-icon-lock {
font-size: 13px;
/* Slight vertical adjustment so the lock
doesn't sit too high, relative to the
other stream icons. */
padding-top: 2px;
}
}
.sidebar-topic-check,
.topic-name,
.topic-markers-and-controls {
cursor: pointer;
}
#left-sidebar-navigation-list .filter-icon i {
color: var(--color-left-sidebar-navigation-icon);
}
#stream_filters,
#left-sidebar-navigation-list {
margin-right: 12px;
}
li.show-more-topics {
& a {
font-size: 12px;
}
}
#streams_inline_icon,
.streams_filter_icon {
float: right;
opacity: 0.5;
padding: 3px;
margin-left: 4px;
&:hover {
opacity: 1;
cursor: pointer;
}
}
.streams_inline_icon_wrapper {
float: right;
margin-right: 8px;
}
.streams_filter_icon.web_public {
margin-right: 10px;
}
.tooltip {
max-width: 18em;
}
#stream_filters {
overflow: visible;
margin-bottom: 5px;
margin-right: 12px;
padding: 0;
font-weight: normal;
.input-append.topic_search_section {
padding: 2px 0 2px calc($topic_indent - $topic_resolve_width);
margin-bottom: 3px;
margin-left: 3px;
& input {
width: calc(100% - 50px);
}
.clear_search_button {
margin-left: -1px;
}
}
& li {
& a:hover {
text-decoration: none;
}
& ul {
margin-left: 0;
&.topic-list li {
padding: 2px 0;
&.filter-topics {
padding-bottom: 0;
position: sticky;
top: calc($sections_vertical_gutter + 43px);
z-index: 2;
}
}
}
}
.stream-with-count.hide_unread_counts {
.masked_unread_count {
display: block;
/* Shift masked dot to align with
the least-significant digit on
unreads in other rows.
We have to do this with margin,
because width or padding will
distort the CSS-created dot. */
margin-right: 3px;
}
.unread_count {
display: none;
}
}
.narrow-filter
> .bottom_left_row:hover
> .stream-with-count.hide_unread_counts {
.masked_unread_count {
display: none;
}
.unread_count {
display: inline;
}
}
.stream-expanded {
.stream-with-count.hide_unread_counts {
.masked_unread_count {
display: none;
}
.unread_count {
display: inline;
}
}
}
.has-unmuted-unreads.hide_unread_counts {
.masked_unread_count {
display: none;
}
.unread_count {
display: inline;
}
}
.inactive_stream:not(.active-filter) {
opacity: 0.5;
}
.toggle_stream_mute {
margin-right: 3px;
opacity: 0.5;
&:hover {
opacity: 1;
}
}
}
.left-sidebar-navigation-area {
& li a {
&:hover {
text-decoration: none;
}
}
}
#left_sidebar_scroll_container {
outline: none;
overflow-x: hidden;
overflow-y: auto;
position: relative;
z-index: 0;
width: 100%;
}
.private_messages_container {
margin-right: 16px;
margin-left: 6px;
z-index: 1;
#private_messages_section_header {
cursor: pointer;
padding: 0 10px 1px 6px;
white-space: nowrap;
#show_all_private_messages {
right: 0;
float: right;
position: absolute;
opacity: 0.7;
text-decoration: none;
color: inherit;
margin-right: 21px;
margin-top: 1px;
&:hover {
opacity: 1;
}
}
.unread_count {
margin-right: 16px;
margin-top: 2px;
}
}
& ul.pm-list {
list-style-type: none;
font-weight: 400;
margin-left: 0;
margin-bottom: 0;
& span.fa-group {
font-size: 90%;
}
& li.pm-list-item {
position: relative;
padding: 1px 10px 1px 4px;
margin-left: 2px;
& a {
text-decoration: none;
color: inherit;
}
.pm_left_col {
min-width: $left_col_size;
& span:not(.user_circle) {
opacity: 0.7;
}
}
}
& li#show_more_private_messages {
cursor: pointer;
padding-right: 26px;
padding-left: 6px;
& a {
font-size: 12px;
}
.unread_count {
margin-top: 2px;
}
}
}
}
#toggle_private_messages_section_icon,
#toggle-top-left-navigation-area-icon {
opacity: 0.7;
margin-left: -15px;
min-width: 12px;
&.fa-caret-right {
position: relative;
left: 3px;
}
&:hover {
opacity: 1;
}
&:focus {
outline: 0;
}
/* This renders an outline when the caret is reached
with the keyboard, although that is not at present
easily accomplished. */
&:focus-visible {
outline: 2px solid var(--color-outline-focus);
}
}
.active_private_messages_section {
#private_messages_section,
#private_messages_list,
#hide_more_private_messages {
background-color: hsl(202deg 56% 91%);
}
#private_messages_section {
border-radius: 4px 4px 0 0;
}
#private_messages_list {
border-radius: 0 0 4px 4px;
}
#more_private_messages_sidebar_title {
font-weight: 600;
}
}
:not(.active-sub-filter) {
&.top_left_row:hover,
&.bottom_left_row:hover {
background-color: var(--color-background-hover-narrow-filter);
border-radius: 4px;
}
}
#stream_filters .narrow-filter.highlighted_stream {
&.active-filter > .bottom_left_row {
background-color: var(--color-background-hover-narrow-filter);
}
&.active-filter .topic-list .bottom_left_row {
background-color: var(--color-background-active-narrow-filter);
}
.bottom_left_row:not(.active-sub-filter) {
background-color: var(--color-background-hover-narrow-filter);
}
}
#login-link-container,
#subscribe-to-more-streams {
text-decoration: none;
margin: 5px auto 5.5px 10px;
margin-bottom: $bottom_scrolling_buffer;
& i {
min-width: 19px;
text-align: center;
&::before {
padding-right: 3px;
}
}
}
ul.filters {
list-style-type: none;
margin-left: 0;
color: hsl(0deg 0% 20% / 100%);
& a {
color: inherit;
&:focus {
text-decoration: none;
}
}
& hr {
margin-top: 10px;
margin-bottom: 10px;
}
.has-only-muted-unreads {
.unread_count {
opacity: 0.5;
}
}
.has-only-muted-mentions .unread_mention_info {
opacity: 0.5;
}
/* This is a noop in the current design, because unread counts for
muted streams have the same opacity, but the logic is here to
be explicit and because the design may change in the future. */
.more_topic_unreads_muted_only .unread_count {
opacity: 0.5;
}
& li.muted_topic,
li.out_of_home_view {
color: hsl(0deg 0% 20% / 50%);
.has-unmuted-mentions .unread_mention_info {
color: hsl(0deg 0% 20%);
}
.stream-privacy {
opacity: 0.5;
}
& .unread_count {
opacity: 0.5;
}
& .masked_unread_count {
opacity: 0.5;
}
.has-unmuted-unreads {
.unread_count {
opacity: 1;
}
}
& li.unmuted_or_followed_topic {
color: var(--color-unmuted-or-followed-topic-list-item);
.unread_count {
opacity: 1;
}
}
}
& li.out_of_home_view {
&:hover {
color: hsla(0deg 0% 20% / 75%);
.stream-privacy {
opacity: 0.75;
}
.unread_count {
opacity: 0.75;
}
.has-unmuted-unreads {
.unread_count {
opacity: 1;
}
}
}
& li.muted_topic {
/* If stream is muted, this resets opacity of muted topics in muted
stream to 1; since opacity is multiplied down through child
elements, this avoids an unreadably low opacity. */
opacity: 1;
}
}
}
li.active-filter,
li.active-sub-filter {
font-weight: 600 !important;
position: relative;
border-radius: 4px;
background-color: var(--color-background-active-narrow-filter);
}
#stream_filters .narrow-filter.active-filter {
.topic-list .filter-topics,
> .bottom_left_row {
background-color: var(--color-background-active-narrow-filter);
border-radius: 4px;
}
}
#left-sidebar-navigation-list-condensed {
display: flex;
justify-content: center;
.left-sidebar-navigation-condensed-item {
/* 24px minimum width from Vlad's design. */
flex: 1 0 24px;
/* Unset padding from individual top_left items */
padding: 0;
border-radius: 4px;
.unread_count {
position: absolute;
}
/* Show the same styles when each item is
hovered or, via the keyboard, the `<a>`
element within receives focus. */
&:hover,
&:focus-within {
background: var(--color-background-hover-narrow-filter);
.unread_count {
top: -6px;
right: -6px;
}
}
&:not(:hover) .unread_count {
top: 2px;
right: 2px;
width: 6px;
height: 6px;
font-size: 0;
padding: 0;
background-color: var(--color-background-unread-counter-dot);
}
&.top_left_starred_messages .unread_count {
display: none;
}
}
.left-sidebar-navigation-icon-container {
/* Unset margin from full nav list anchor elements. */
margin: 0;
/* Horizontally center icons within their boxes. */
text-align: center;
&:focus {
/* Unset inherited :focus outline. */
outline: 0;
}
}
.active-filter {
/* Don't display a background on condensed icons. */
background: unset;
}
.filter-icon {
display: flex;
align-items: center;
justify-content: center;
/* TODO: Set this 24px height value as a variable.
Keep filter-icon height the full height of the box. */
height: 24px;
color: var(--color-left-sidebar-navigation-icon);
}
}
#left-sidebar-navigation-list {
margin-bottom: $sections_vertical_gutter;
.left-sidebar-navigation-label-container {
.left-sidebar-navigation-label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.top_left_starred_messages .unread_count,
.top_left_drafts .unread_count,
.top_left_scheduled_messages .unread_count,
.condensed-views-popover-menu .unread_count {
background-color: unset;
color: inherit;
border: 0.5px solid var(--color-border-unread-counter);
/* The border takes up space, so we need to
subtract 1px from the usual 2px margin-top */
margin-top: 1px !important;
}
li.top_left_all_messages,
li.top_left_mentions,
li.top_left_starred_messages,
li.top_left_drafts,
li.top_left_inbox,
li.top_left_recent_view,
li.top_left_scheduled_messages {
/* TODO: Clean this up with other vdots
positioning stuff. */
position: relative;
}
/* Don't show the scheduled messages item... */
li.top_left_scheduled_messages {
display: none;
/* ...unless there are scheduled messages to show. */
&.show-with-scheduled-messages {
/* Use display: grid to preserve the grid
layout when visible. */
display: grid;
}
}
.top_left_row {
/* The row grid for the outer .top_left_row
is chiefly for lefthand spacing and placing
the inner row content and vdots. */
grid-template-columns: 7px 0 minmax(0, 1fr) 0 30px 0;
.sidebar-menu-icon {
grid-area: ending-anchor-element;
justify-self: center;
/* TODO: Clean up the .sidebar-menu-icon descendant
styles up and down the left sidebar. */
position: static;
font-size: 17px;
text-align: center;
}
}
.left-sidebar-navigation-label-container {
grid-area: row-content;
/* The label container itself is also a grid,
for laying out the items that are its
children. Same template areas, different
column widths. */
grid-template-columns: 0 22px minmax(0, 1fr) max-content 0 0;
/* This is a legacy value, from a former
1px of top padding on top_left_row plus
an inner 1px top margin on `<a>` elements.
These are added here, rather than on the label
container, to keep all hovered/highlighted areas
clickable.
This complicates true centering within a
row highlight. It might be better to make
these both 2px.
*/
padding-top: 2px;
padding-bottom: 1px;
.filter-icon {
grid-area: starting-anchor-element;
text-align: center;
}
.left-sidebar-navigation-label {
grid-area: row-content;
}
.unread_count {
grid-area: markers-and-controls;
}
}
.conversation-partners {
line-height: 1.25;
display: flex;
width: 100%;
overflow: hidden;
}
.conversation-partners .status-emoji {
/* Prevent status emoji from colliding
with unread counts. */
margin-right: 3px;
}
/* New .topic-box grid definitions here. */
#views-label-container,
.top_left_row,
.left-sidebar-navigation-label-container,
.subscription_block,
.topic-box {
display: grid;
align-items: center;
/* This general pattern of elements applies to every single row in the left
sidebar, to some degree or another. Eventually, these template areas
could be applied to all rows, with different `grid-template-column`
values applied as needed (and shared as needed). For example, an element
with no "starting-offset" sets that area to `0`; so too with other non-
existent elements.
The offsets themselves are meant to greedily assign all of the available
horizontal space to the content area of the row. That space can then be
modified or reassigned as needed, without running up against `padding`
(which alters the box size) or `margin` (which notoriously bleeds outside
of the element it's defined on). */
grid-template-areas: "starting-offset starting-anchor-element row-content markers-and-controls ending-anchor-element ending-offset";
}
#views-label-container {
grid-template-columns:
0 15px minmax(0, 0.5fr) minmax(0, 1fr)
20px 20px;
/* Base height on 24px icon-target area from Vlad's design. */
grid-template-rows: 24px;
/* TODO: Rewrite the `--left-sidebar-collapse-widget-gutter`
value and the styles dependent on it so that this kind of
1990s layout shenanigans is made unnecessary. */
margin-left: -3px;
cursor: pointer;
&.showing-expanded-navigation {
/* When the expanded navigation is visible,
hide the condensed navigation's controls. */
#left-sidebar-navigation-list-condensed,
.left-sidebar-navigation-menu-icon {
display: none;
}
/* Give the sidebar title through the end of the markers
area, if needed. */
.sidebar-title {
grid-column: row-content-start / markers-and-controls-end;
}
}
/* Use a next-sibling combinator (+) to use CSS to show and hide
filter rows as needed, based on the narrow. */
&.showing-condensed-navigation {
+ #left-sidebar-navigation-list {
/* When the navigation area is condensed, hide all
the rows in the full navigation list... */
& .top_left_row {
display: none;
}
/* ...except when there is an active filter in place:
that row should still be shown. */
& .top_left_row.active-filter {
display: grid;
}
}
}
#toggle-top-left-navigation-area-icon {
grid-area: starting-anchor-element;
/* Remove negative left margin. This should be cleaned
up along with the `--left-sidebar-collapse-widget-gutter`
matters above. */
margin-left: 0;
}
.sidebar-title {
grid-area: row-content;
/* Override heading margin from Bootstrap. */
margin: 0;
/* Show an ellipsis on the VIEWS header when
it won't sit adjacent the icons in their
most condensed presentation. */
overflow: hidden;
text-overflow: ellipsis;
}
#left-sidebar-navigation-list-condensed {
margin: 0;
grid-area: markers-and-controls;
}
.left-sidebar-navigation-menu-icon {
grid-area: ending-anchor-element;
/* Horizontally center vdots. */
justify-self: center;
/* Properly size vdots. */
font-size: 17px;
/* Occupy same clickable height as
other condensed-view icons */
height: 24px;
/* Vertically center dots with
flexbox. */
display: flex;
align-items: center;
color: var(--color-left-sidebar-header-vdots-visible);
&:hover {
color: var(--color-vdots-hover);
}
}
}
.condensed-views-popover-menu {
.left-sidebar-popover-icon-label-count {
display: flex;
align-items: baseline;
}
.filter-icon {
align-self: center;
height: 15px;
}
.left-sidebar-navigation-label {
flex: 1 0 0;
margin-left: 3px;
}
.unread_count {
margin-left: 6px;
border-color: var(--color-border-unread-counter-popover-menu);
}
}
.subscription_block {
grid-template-columns:
7px 22px minmax(0, 1fr) minmax(0, max-content)
30px 0;
white-space: nowrap;
.stream-privacy {
grid-area: starting-anchor-element;
}
.stream-name {
grid-area: row-content;
}
}
.topic-box {
/* Padding from original .topic-box definition. */
padding-top: 1px;
grid-template-columns:
25px $topic_resolve_width minmax(0, 1fr) minmax(0, max-content)
30px 0;
}
.topic-box .zero_count {
display: none;
}
.sidebar-topic-check {
grid-area: starting-anchor-element;
font-size: 15px;
height: 20px;
}
.topic-name {
grid-area: row-content;
padding: 1px 0;
/* TODO: We should figure out how to remove this without changing the spacing */
line-height: 1.1;
/* TODO: Consolidate these styles with conversation partners and stream name
once grid rewrite is complete on all sidebar rows.
Also: note that these styles will be moot for topic names once we allow
for multiline topics. If we hold multiline topics to a certain number
of lines, we'll likely need a JavaScript-based solution like Clamp.js
to display an ellipsis on the final visible line. */
white-space: nowrap;
/* Both `hidden` and `clip` are shown for the sake
of older browsers that do not support `clip`. */
overflow-x: hidden;
overflow-x: clip;
text-overflow: ellipsis;
}
.stream-markers-and-controls,
.topic-markers-and-controls {
grid-area: markers-and-controls;
display: flex;
/* Present a uniform space between icons */
gap: 5px;
align-items: center;
.unread_mention_info {
/* Unset margin in favor of flex gap. */
margin: 0;
}
.unread_count {
/* Height is set here by the flexbox; this
decouples .unread_count from the app-wide
definition. */
height: auto;
}
}
.bottom_left_row .subscription_block .sidebar-menu-icon,
.bottom_left_row .topic-box .sidebar-menu-icon {
position: static;
grid-area: ending-anchor-element;
}
.conversation-partners-list,
.stream-name {
flex: auto;
min-width: 0;
white-space: nowrap;
overflow-x: hidden;
overflow-x: clip;
text-overflow: ellipsis;
padding: 1px $before_unread_count_padding 1px 0;
}
.conversation-partners-list {
/* Don't allow growth, so that status emoji
remain adjacent the username. */
flex: 0 1 auto;
}
.left_sidebar_menu_icon_visible {
display: block !important;
}
/*
All of our left sidebar handlers use absolute
positioning. We should fix that.
*/
.top_left_row .sidebar-menu-icon,
.bottom_left_row .sidebar-menu-icon {
position: absolute;
display: none;
top: 1px;
right: 0;
font-size: 1em;
text-align: center;
padding: 0 6px;
& i {
padding-right: 0.35em;
display: inline-block;
width: 13px;
font-size: 17px;
vertical-align: middle;
}
/*
If you hover directly over the ellipsis itself,
show it in black.
*/
&:hover {
color: var(--color-vdots-hover);
}
/*
Hover does not work for touch-based devices like mobile phones.
Hence the the icons does not appear, making the user unaware of its
presence on such devices. The following media property displays the
icon by default for such behaviour.
*/
@media (hover: none) {
display: block;
/* Show dots on touchscreens in a less distracting,
lighter shade. */
color: var(--color-vdots-hint);
}
}
/*
When you hover over list items, we hover
the vdots in light gray.
The stream icon should always display when
any topic is hovered, which is why it gets
a more specific selector here.
*/
#stream_filters li:hover .stream-sidebar-menu-icon,
.top_left_row:hover .sidebar-menu-icon,
.bottom_left_row:hover .sidebar-menu-icon {
display: inline;
cursor: pointer;
color: var(--color-vdots-visible);
/*
If you hover directly over the vdots icon,
show it in black.
*/
&:hover {
color: var(--color-vdots-hover);
}
}
/*
For topic ellipsis-v(vertical 3 dots) we use a slightly smaller
font to show they're "lower" in the hierarchy,
which also affects it positioning.
*/
.bottom_left_row .topic-sidebar-menu-icon {
font-size: 0.9em;
/* Strip the line height back to the font size,
so that vertical positioning is handled by
grid exclusively. */
line-height: 1;
}
ul.topic-list {
list-style-type: none;
font-weight: normal;
}
li.topic-list-item {
position: relative;
padding-right: 5px;
}
.pm-box {
display: flex;
padding-top: 1px;
margin-right: 16px;
align-items: baseline; /* Sets .user_circle alignment relative to text; standard icons do not participate in flex. */
.user_circle {
min-width: 8px;
height: 8px;
margin-top: 0;
margin-bottom: 0;
margin-left: 2px;
position: relative;
top: 0;
}
.zulip-icon.zulip-icon-bot {
font-size: 90%; /* Reduce the bulkiness of this icon */
padding: 3px 0 3px 1px; /* Shift reduced icon a pixel left to maintain horizontal centering. */
}
}
.zero-pm-unreads .pm-box {
margin-right: 15px;
}
.zoom-out {
#topics_header {
display: none;
}
.zoom-out-hide {
display: none;
}
}
#topics_header {
position: sticky;
top: 0;
z-index: 2;
margin-right: 10px;
padding-top: $sections_vertical_gutter;
color: hsl(0deg 0% 43%);
background-color: var(--color-background);
.show-all-streams {
color: inherit;
text-decoration: none;
text-transform: uppercase;
margin-left: calc($far_left_gutter_size + 2px);
& i {
margin: 0 6px 0 13px;
position: relative;
top: 1px;
}
}
}
#streams_header {
margin-right: 12px;
cursor: pointer;
padding: $sections_vertical_gutter 0 3px calc($far_left_gutter_size + 2px);
position: sticky;
background-color: var(--color-background);
/* Ideally, 0px should work here, but maybe simplebar is doing something
that is creating `0.5px` extra gap in zoomed-in windows. */
top: -0.5px;
z-index: 1;
.input-append {
white-space: nowrap;
margin-bottom: 10px;
& input {
padding-right: 20px;
}
.clear_search_button {
margin-left: -1px;
}
}
}
.streams_subheader {
font-size: 0.8em;
font-weight: normal;
padding-left: $far_left_gutter_size;
cursor: pointer;
text-align: center;
margin-right: 12px;
color: hsl(240deg 10% 50%);
& span {
display: flex;
flex-direction: row;
width: 100%;
left: 0.5em;
right: 0.5em;
opacity: 0.5;
}
& span::before,
span::after {
content: " ";
flex: 1 1;
vertical-align: middle;
margin: auto;
border: 0.5px solid hsl(240deg 10% 50%);
opacity: 0.2;
}
& span::before {
margin-right: 0.5em;
}
& span::after {
margin-left: 0.5em;
}
}
.stream-list-filter {
width: 216px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.topic-list-filter {
/* Input width = 100% - 30px right-margin - 6px right-padding */
/* To keep the right edge of input along with its borders inline with other
topic items we consider to subtract the space given for right margin of
other items, and right padding of input element. */
width: calc(100% - 36px);
}
.zero_count {
visibility: hidden;
}
.zero-topic-unreads.show-more-topics .topic-box {
margin-right: 30px;
}
.searching-for-more-topics img {
height: 16px;
margin-left: 6px;
}
.zoom-in {
.narrow-filter > .bottom_left_row {
position: sticky;
top: calc($sections_vertical_gutter + 20px);
z-index: 2;
padding-bottom: 1px;
background-color: var(--color-background);
}
#subscribe-to-more-streams,
.show-more-topics {
display: none;
}
&.private_messages_container ul.pm-list {
margin-bottom: $bottom_scrolling_buffer;
}
#more_private_messages_sidebar_title {
display: inline;
}
#hide_more_private_messages {
display: block;
text-decoration: none;
color: inherit;
font-size: 12px;
& span {
display: block;
padding: 2px 0 2px 4px;
}
&:hover {
& span {
background-color: hsl(120deg 12.3% 71.4% / 38%);
border-radius: 4px;
}
}
}
.zoom-in-hide {
display: none;
}
.zoom-in-sticky {
position: sticky;
top: 0;
z-index: 1;
padding: 3px 0 3px $far_left_gutter_size;
}
#show_all_private_messages {
margin-right: 5px !important;
}
}