mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 04:52:12 +00:00
This follow-up commit replaces the current left sidebar topic list filter input implementation with the redesigned input_wrapper component. This commit also serves as the base for supporting inputs using the search_pill_widget, and thus adjusts the previously defined logic at certain places to ensure that the input pills are handled and displayed accurately. Fixes part of #34476.
1964 lines
54 KiB
CSS
1964 lines
54 KiB
CSS
.left-sidebar-title {
|
|
color: var(--color-text-sidebar-heading);
|
|
opacity: var(--opacity-sidebar-heading);
|
|
transition: opacity 140ms linear;
|
|
font-size: inherit;
|
|
font-weight: var(--font-weight-sidebar-heading);
|
|
letter-spacing: var(--letter-spacing-sidebar-heading);
|
|
/* Override heading margin from Bootstrap. */
|
|
margin: 0;
|
|
/* Show an ellipsis on a heading when
|
|
it won't sit adjacent other icons
|
|
or controls in the row. */
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
#left-sidebar .unread_count {
|
|
user-select: none;
|
|
}
|
|
|
|
.sidebar-topic-check,
|
|
.topic-markers-and-unreads {
|
|
cursor: pointer;
|
|
}
|
|
|
|
#left-sidebar-navigation-list .filter-icon i {
|
|
color: var(--color-left-sidebar-navigation-icon);
|
|
}
|
|
|
|
#stream_filters,
|
|
#left-sidebar-navigation-list {
|
|
margin-right: var(--left-sidebar-right-margin);
|
|
}
|
|
|
|
#streams_inline_icon,
|
|
.streams_filter_icon {
|
|
color: var(--color-left-sidebar-heads-up-icon);
|
|
border-radius: 3px;
|
|
|
|
&:hover {
|
|
color: var(--color-left-sidebar-heads-up-icon-hover);
|
|
background-color: var(
|
|
--background-color-left-sidebar-heads-up-icon-hover
|
|
);
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
|
|
.streams_filter_icon.web_public {
|
|
margin-right: 10px;
|
|
}
|
|
|
|
.masked_unread_count {
|
|
/* 8px at 16px/14em */
|
|
font-size: 0.5em;
|
|
display: none;
|
|
/* Masked unreads display as flex when revealed. */
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: var(--color-unread-counter-muted);
|
|
width: var(--left-sidebar-single-digit-unread-width);
|
|
}
|
|
|
|
.selected-home-view {
|
|
&.hide-unread-messages-count {
|
|
.masked_unread_count {
|
|
/* Adding margin-right aligns the .masked_unread_count with the rest of the masked unread counts. */
|
|
margin-right: var(--left-sidebar-unread-offset);
|
|
}
|
|
}
|
|
}
|
|
|
|
.selected-home-view,
|
|
#streams_header {
|
|
&.hide-unread-messages-count {
|
|
.masked_unread_count {
|
|
display: flex;
|
|
grid-area: markers-and-unreads;
|
|
justify-self: end;
|
|
visibility: visible;
|
|
}
|
|
|
|
.unread_count {
|
|
visibility: hidden;
|
|
}
|
|
/* When message summary count is 0, we dont want to show unread_count or masked_unread_count. */
|
|
.unread_count.hide + .masked_unread_count {
|
|
visibility: hidden;
|
|
}
|
|
}
|
|
}
|
|
|
|
.selected-home-view:hover,
|
|
#streams_header:hover,
|
|
.selected-home-view.top-left-active-filter {
|
|
&.hide-unread-messages-count {
|
|
.masked_unread_count {
|
|
visibility: hidden;
|
|
position: absolute;
|
|
}
|
|
|
|
.unread_count {
|
|
visibility: visible;
|
|
}
|
|
}
|
|
}
|
|
|
|
#stream_filters {
|
|
overflow: visible;
|
|
margin-bottom: 5px;
|
|
padding: 0;
|
|
font-weight: normal;
|
|
|
|
.topic_search_section {
|
|
margin: 3px 0;
|
|
}
|
|
|
|
& li {
|
|
& .sidebar-topic-name:hover {
|
|
text-decoration: none;
|
|
}
|
|
|
|
& ul {
|
|
margin-left: 0;
|
|
|
|
&.topic-list li {
|
|
padding: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
.stream-with-count.hide_unread_counts {
|
|
.masked_unread_count {
|
|
display: flex;
|
|
}
|
|
|
|
.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 {
|
|
.channel-new-topic-button {
|
|
display: flex;
|
|
}
|
|
|
|
.subscription_block .sidebar-menu-icon {
|
|
display: flex;
|
|
color: var(--color-vdots-visible);
|
|
}
|
|
|
|
.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;
|
|
}
|
|
}
|
|
|
|
.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: hidden auto;
|
|
position: relative;
|
|
z-index: 0;
|
|
width: 100%;
|
|
|
|
.direct-messages-container {
|
|
margin-left: 0;
|
|
}
|
|
}
|
|
|
|
#hide-more-direct-messages,
|
|
#direct-messages-section-header {
|
|
grid-template-columns:
|
|
0 var(--left-sidebar-header-icon-toggle-width) 0 minmax(0, 1fr)
|
|
minmax(0, max-content) minmax(0, max-content) var(
|
|
--left-sidebar-vdots-width
|
|
)
|
|
0;
|
|
}
|
|
|
|
#hide-more-direct-messages {
|
|
/* Keep the DM zoom-out option hidden until zoomed-in. */
|
|
display: none;
|
|
margin-right: var(--left-sidebar-right-margin);
|
|
line-height: var(--line-height-sidebar-row);
|
|
text-decoration: none;
|
|
color: inherit;
|
|
|
|
.hide-more-direct-messages-text {
|
|
color: var(--color-text-sidebar-action-heading);
|
|
font-size: var(--font-size-sidebar-action-heading);
|
|
font-weight: var(--font-weight-sidebar-action-heading);
|
|
font-variant: var(--font-variant-sidebar-action-heading);
|
|
text-transform: var(--text-transform-sidebar-action-heading);
|
|
grid-area: row-content;
|
|
}
|
|
|
|
&:hover {
|
|
background-color: var(--color-background-sidebar-action-heading-hover);
|
|
box-shadow: inset 0 0 0 1px var(--color-shadow-sidebar-row-hover);
|
|
border-radius: 4px;
|
|
}
|
|
}
|
|
|
|
#direct-messages-section-header {
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
border-radius: 4px;
|
|
|
|
/* Prevent hover styles set on other rows when zoomed in. */
|
|
&:not(.zoom-in):hover {
|
|
background-color: var(--color-background-hover-narrow-filter);
|
|
box-shadow: inset 0 0 0 1px var(--color-shadow-sidebar-row-hover);
|
|
|
|
.left-sidebar-title,
|
|
.sidebar-heading-icon {
|
|
opacity: var(--opacity-sidebar-heading-hover);
|
|
}
|
|
}
|
|
|
|
#toggle-direct-messages-section-icon {
|
|
grid-area: starting-anchor-element;
|
|
/* Horizontally center the icon in its allotted grid area. */
|
|
justify-self: center;
|
|
}
|
|
|
|
.left-sidebar-title {
|
|
grid-area: row-content;
|
|
}
|
|
|
|
.heading-markers-and-unreads {
|
|
grid-area: markers-and-unreads;
|
|
display: flex;
|
|
gap: 5px;
|
|
align-items: center;
|
|
/* Extra margin for unreads. */
|
|
margin-right: var(--left-sidebar-unread-offset);
|
|
|
|
&:has(.unread_count:empty) {
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
|
|
#compose-new-direct-message,
|
|
#show-all-direct-messages {
|
|
color: var(--color-left-sidebar-heads-up-icon);
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-decoration: none;
|
|
margin: 2px 0;
|
|
border-radius: 3px;
|
|
grid-row: 1 / 1;
|
|
|
|
&:hover {
|
|
color: var(--color-left-sidebar-heads-up-icon-hover);
|
|
background-color: var(
|
|
--background-color-left-sidebar-heads-up-icon-hover
|
|
);
|
|
}
|
|
|
|
@media (hover: none) {
|
|
display: flex;
|
|
}
|
|
}
|
|
|
|
&.hover-over-dm-section,
|
|
&.zoom-in,
|
|
&:hover {
|
|
#compose-new-direct-message,
|
|
#show-all-direct-messages {
|
|
display: flex;
|
|
}
|
|
}
|
|
}
|
|
|
|
.direct-messages-container {
|
|
/* Properly offset all the grid rows
|
|
in the DM section. */
|
|
margin-right: var(--left-sidebar-right-margin);
|
|
|
|
& ul.dm-list {
|
|
list-style-type: none;
|
|
font-weight: 400;
|
|
margin-left: 0;
|
|
margin-bottom: 0;
|
|
line-height: var(--line-height-sidebar-row-prominent);
|
|
|
|
& li.dm-list-item {
|
|
& a {
|
|
text-decoration: none;
|
|
color: inherit;
|
|
}
|
|
|
|
.zulip-icon:not(.user-circle) {
|
|
color: var(--color-left-sidebar-dm-partners-icon);
|
|
vertical-align: -0.2em;
|
|
}
|
|
}
|
|
|
|
& li#show-more-direct-messages {
|
|
color: var(--color-text-sidebar-action-heading);
|
|
font-size: var(--font-size-sidebar-action-heading);
|
|
font-weight: var(--font-weight-sidebar-action-heading);
|
|
letter-spacing: var(--letter-spacing-sidebar-action-heading);
|
|
font-variant: var(--font-variant-sidebar-action-heading);
|
|
text-transform: var(--text-transform-sidebar-action-heading);
|
|
cursor: pointer;
|
|
/* The 'more conversations' line has no icons,
|
|
so vertically align the text with the unread
|
|
count, when one appears there. */
|
|
align-items: baseline;
|
|
|
|
&:hover {
|
|
background-color: var(
|
|
--color-background-sidebar-action-heading-hover
|
|
);
|
|
|
|
.dm-name {
|
|
color: var(--color-text-sidebar-action-heading-hover);
|
|
}
|
|
}
|
|
|
|
.unread_count {
|
|
margin-top: 2px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.zulip-icon-heading-triangle-right {
|
|
transition:
|
|
opacity 140ms linear,
|
|
rotate 140ms linear;
|
|
}
|
|
|
|
.zulip-icon-heading-triangle-right.rotate-icon-down {
|
|
rotate: 90deg;
|
|
}
|
|
|
|
.zulip-icon-heading-triangle-right.rotate-icon-right {
|
|
rotate: 0deg;
|
|
}
|
|
|
|
#toggle-direct-messages-section-icon,
|
|
#toggle-top-left-navigation-area-icon {
|
|
color: var(--color-text-sidebar-heading);
|
|
opacity: var(--opacity-sidebar-heading-icon);
|
|
|
|
&: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-direct-messages-section {
|
|
background-color: var(--color-background-active-narrow-filter);
|
|
|
|
&#direct-messages-section-header {
|
|
border-radius: 4px 4px 0 0;
|
|
}
|
|
|
|
#direct-messages-list {
|
|
border-radius: 0 0 4px 4px;
|
|
}
|
|
}
|
|
|
|
.top_left_row,
|
|
.bottom_left_row {
|
|
/* Ensure a border radius on any interactive
|
|
state that might show a highlight. */
|
|
border-radius: 4px;
|
|
|
|
&:hover,
|
|
&:has(.left_sidebar_menu_icon_visible) {
|
|
background-color: var(--color-background-hover-narrow-filter);
|
|
box-shadow: inset 0 0 0 1px var(--color-shadow-sidebar-row-hover);
|
|
|
|
.sidebar-topic-check {
|
|
background-color: var(
|
|
--color-background-opaque-hover-narrow-filter
|
|
);
|
|
}
|
|
}
|
|
|
|
&:has(.sidebar-topic-action-heading):hover {
|
|
background-color: var(--color-background-sidebar-action-heading-hover);
|
|
}
|
|
|
|
&:has(a.left-sidebar-navigation-label-container:focus-visible) {
|
|
outline: 2px solid var(--color-outline-focus);
|
|
outline-offset: -2px;
|
|
background-color: var(--color-background-hover-narrow-filter);
|
|
}
|
|
|
|
.left-sidebar-navigation-label-container:focus {
|
|
outline: none;
|
|
}
|
|
|
|
&.active-filter,
|
|
&.top-left-active-filter,
|
|
&.active-sub-filter {
|
|
&:has(.left_sidebar_menu_icon_visible) {
|
|
background-color: var(--color-background-active-narrow-filter);
|
|
}
|
|
}
|
|
}
|
|
|
|
#stream_filters .narrow-filter:has(a.stream-name:focus-visible),
|
|
#stream_filters .narrow-filter.highlighted_stream {
|
|
&.active-filter > .bottom_left_row {
|
|
background-color: var(--color-background-hover-narrow-filter);
|
|
}
|
|
|
|
& > .bottom_left_row {
|
|
outline: 2px solid var(--color-outline-focus);
|
|
outline-offset: -2px;
|
|
}
|
|
|
|
&.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);
|
|
}
|
|
}
|
|
|
|
#stream_filters
|
|
.narrow-filter
|
|
.topic-list
|
|
.bottom_left_row:has(a.sidebar-topic-name:focus-visible),
|
|
#direct-messages-list
|
|
.dm-list
|
|
.bottom_left_row:has(a.conversation-partners:focus-visible) {
|
|
outline: 2px solid var(--color-outline-focus);
|
|
outline-offset: -2px;
|
|
background-color: var(--color-background-hover-narrow-filter);
|
|
}
|
|
|
|
#stream_filters .narrow-filter,
|
|
#direct-messages-list .bottom_left_row {
|
|
a.stream-name:focus,
|
|
a.sidebar-topic-name:focus,
|
|
a.conversation-partners:focus,
|
|
a.sidebar-topic-action-heading:focus {
|
|
outline: none;
|
|
text-decoration: none;
|
|
}
|
|
}
|
|
|
|
#subscribe-to-more-streams,
|
|
#login-to-more-streams {
|
|
/* --left-sidebar-bottom-scrolling-buffer is to prevent the row from
|
|
being cut off, and --sidebar-bottom-spacing is extra padding. */
|
|
margin: 5px var(--left-sidebar-right-margin)
|
|
calc(
|
|
var(--left-sidebar-bottom-scrolling-buffer) +
|
|
var(--sidebar-bottom-spacing)
|
|
)
|
|
0;
|
|
padding-left: var(--left-sidebar-toggle-width-offset);
|
|
border-radius: 4px;
|
|
text-decoration: none;
|
|
|
|
&:hover {
|
|
background: var(--color-background-sidebar-action-heading-hover);
|
|
box-shadow: inset 0 0 0 1px var(--color-shadow-sidebar-row-hover);
|
|
color: var(--color-text-sidebar-action-heading-hover);
|
|
}
|
|
|
|
.subscribe-more-link {
|
|
display: grid;
|
|
grid-template:
|
|
"plus-icon . row-text" minmax(
|
|
var(--line-height-sidebar-row-prominent),
|
|
auto
|
|
)
|
|
/ var(--left-sidebar-icon-column-width) var(
|
|
--left-sidebar-icon-content-gap
|
|
)
|
|
minmax(0, 1fr);
|
|
align-items: center;
|
|
line-height: 1;
|
|
color: var(--color-text-sidebar-action-heading);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.subscribe-more-label {
|
|
grid-area: row-text;
|
|
/* Because the label is run in small caps, we do a font-metrics-based
|
|
adjustment of its top margin to keep the text vertically aligned
|
|
with the square [+] icon (whose shape leaves absolutely no room
|
|
for error when it comes to centering). Going back to the font metrics
|
|
outlined in web/src/information_density.ts, we can offset against the
|
|
space reserved for descenders, and take half that value to pull the
|
|
text up: 400 / (400 + 1025) ~= 0.28; half of 0.28 is 0.14, so
|
|
`margin-top: -0.14em`. However, it looks as though a slight adjustment
|
|
to -0.12em produces a slightly more pleasing result, which makes sense
|
|
because mathematical centering and the perception of center don't
|
|
always match. */
|
|
margin-top: -0.12em;
|
|
padding: 3px 0;
|
|
font-size: var(--font-size-sidebar-action-heading);
|
|
font-weight: var(--font-weight-sidebar-action-heading);
|
|
font-variant: var(--font-variant-sidebar-action-heading);
|
|
font-feature-settings: var(
|
|
--font-feature-settings-sidebar-action-heading
|
|
);
|
|
text-transform: var(--text-transform-sidebar-action-heading);
|
|
}
|
|
|
|
.subscribe-more-icon {
|
|
/* Scale the icon with the action-heading font-size
|
|
for better vertical centering. */
|
|
font-size: var(--font-size-sidebar-action-heading);
|
|
}
|
|
}
|
|
|
|
ul.filters {
|
|
list-style-type: none;
|
|
margin-left: 0;
|
|
line-height: var(--line-height-sidebar-row-prominent);
|
|
|
|
.sidebar-topic-name,
|
|
.left-sidebar-navigation-label-container {
|
|
color: var(--color-text-sidebar-row);
|
|
|
|
&:hover {
|
|
/* Push back against a:hover color in dark_theme.css */
|
|
color: var(--color-text-sidebar-row) !important;
|
|
}
|
|
|
|
&:focus {
|
|
text-decoration: none;
|
|
}
|
|
}
|
|
|
|
.sidebar-topic-action-heading {
|
|
&:focus {
|
|
color: var(--color-text-sidebar-action-heading);
|
|
}
|
|
}
|
|
|
|
& hr {
|
|
margin-top: 10px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.has-only-muted-unreads {
|
|
.unread_count {
|
|
opacity: var(--opacity-left-sidebar-muted);
|
|
}
|
|
|
|
&:hover .unread_count {
|
|
opacity: var(--opacity-left-sidebar-muted-hover);
|
|
}
|
|
}
|
|
|
|
.has-only-muted-mentions {
|
|
.unread_mention_info {
|
|
opacity: var(--opacity-left-sidebar-muted);
|
|
}
|
|
|
|
&:hover .unread_mention_info {
|
|
opacity: var(--opacity-left-sidebar-muted-hover);
|
|
}
|
|
}
|
|
|
|
/* 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: var(--opacity-left-sidebar-muted);
|
|
}
|
|
|
|
.zulip-icon-follow {
|
|
opacity: 0.5;
|
|
|
|
&:hover {
|
|
opacity: 1;
|
|
color: var(--color-left-sidebar-follow-icon-hover);
|
|
}
|
|
}
|
|
|
|
& li.muted_topic {
|
|
.sidebar-topic-check,
|
|
.sidebar-topic-name,
|
|
.unread_count {
|
|
opacity: var(--opacity-left-sidebar-muted);
|
|
}
|
|
|
|
&:hover {
|
|
.sidebar-topic-check,
|
|
.sidebar-topic-name,
|
|
.unread_count {
|
|
opacity: var(--opacity-left-sidebar-muted-hover);
|
|
}
|
|
}
|
|
}
|
|
|
|
& li.out_of_home_view,
|
|
.inactive_stream:not(.active-filter) {
|
|
.stream-privacy,
|
|
.stream-name,
|
|
.channel-new-topic-button,
|
|
.unread_count,
|
|
.masked_unread_count,
|
|
.sidebar-menu-icon {
|
|
opacity: var(--opacity-left-sidebar-muted);
|
|
}
|
|
|
|
&:hover {
|
|
.stream-privacy,
|
|
.stream-name,
|
|
.channel-new-topic-button,
|
|
.unread_count,
|
|
.masked_unread_count,
|
|
.sidebar-menu-icon {
|
|
opacity: var(--opacity-left-sidebar-muted-hover);
|
|
}
|
|
}
|
|
|
|
.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.active-filter,
|
|
li.top-left-active-filter,
|
|
li.active-sub-filter {
|
|
font-weight: 600 !important;
|
|
position: relative;
|
|
border-radius: 4px;
|
|
color: var(--color-text-active-narrow-filter);
|
|
background-color: var(--color-background-active-narrow-filter);
|
|
|
|
&:hover {
|
|
background-color: var(--color-background-active-narrow-filter);
|
|
|
|
.sidebar-topic-check {
|
|
/* This variable is only set and used in dark mode. */
|
|
background-color: var(
|
|
--color-background-opaque-hover-active-narrow-filter
|
|
);
|
|
}
|
|
}
|
|
|
|
.sidebar-topic-check {
|
|
background-color: var(--color-background-active-narrow-filter);
|
|
}
|
|
|
|
.sidebar-topic-name-inner {
|
|
color: var(--color-text-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;
|
|
|
|
&:hover {
|
|
background-color: var(--color-background-hover-narrow-filter);
|
|
}
|
|
}
|
|
}
|
|
|
|
#left-sidebar-navigation-list-condensed {
|
|
display: flex;
|
|
justify-content: center;
|
|
|
|
.left-sidebar-navigation-condensed-item {
|
|
/* 24px minimum width from Vlad's design.
|
|
however, we want to permit growing and
|
|
shrinking to keep icons reasonably spaced
|
|
across different information-density
|
|
settings. */
|
|
flex: 1 1 24px;
|
|
/* Unset padding from individual top_left items */
|
|
padding: 0;
|
|
border-radius: 4px;
|
|
/* Set a positioning context for the unread dot. */
|
|
position: relative;
|
|
|
|
.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-navigation-item-hover);
|
|
|
|
.unread_count {
|
|
/* 6px at 12px/1em */
|
|
top: -0.5em;
|
|
right: -0.5em;
|
|
background: var(--color-background-unread-counter-no-alpha);
|
|
}
|
|
}
|
|
|
|
&:not(:hover) .unread_count {
|
|
/* .unread_count has its based font-size set to 12px at 14px/em. */
|
|
/* 2px, 6px at 12px/1em */
|
|
top: 0.1667em;
|
|
right: 0.1667em;
|
|
width: 0.5em;
|
|
height: 0.5em;
|
|
padding: 0;
|
|
color: transparent;
|
|
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;
|
|
}
|
|
}
|
|
|
|
.top-left-active-filter {
|
|
/* Don't display a background on condensed icons. */
|
|
background: unset;
|
|
}
|
|
|
|
.filter-icon {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
/* Enlarge icons slightly in condensed views. */
|
|
/* 15px at 16px/1em */
|
|
font-size: 0.9375em;
|
|
/* 24px at 15px/1em */
|
|
height: 1.6em;
|
|
color: var(--color-left-sidebar-navigation-icon);
|
|
}
|
|
}
|
|
|
|
#left-sidebar-navigation-list {
|
|
margin-bottom: var(--left-sidebar-sections-vertical-gutter);
|
|
display: grid;
|
|
line-height: var(--line-height-sidebar-row);
|
|
/* Explicitly ensure parity with the line-height
|
|
for the sake of low-resolution screens, whose
|
|
font-rendering and rounding may cause icons
|
|
to appear out of alignment. This grid feature should
|
|
only apply in the expanded-navigation view. */
|
|
grid-auto-rows: var(--line-height-sidebar-row);
|
|
|
|
.left-sidebar-navigation-label-container {
|
|
.left-sidebar-navigation-label {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Don't show unread counts on views... */
|
|
.top_left_my_reactions,
|
|
.top_left_inbox,
|
|
.top_left_recent_view,
|
|
.top_left_all_messages {
|
|
.unread_count {
|
|
visibility: hidden;
|
|
}
|
|
/* ...unless it's the selected home view. */
|
|
&.selected-home-view .unread_count {
|
|
visibility: visible;
|
|
}
|
|
}
|
|
|
|
.sidebar-menu-icon.hide {
|
|
visibility: hidden;
|
|
}
|
|
|
|
/* Don't show the scheduled messages item... */
|
|
li.top_left_reminders,
|
|
li.top_left_scheduled_messages {
|
|
display: none;
|
|
/* ...unless there are scheduled messages to show. */
|
|
&.show-with-reminders,
|
|
&.show-with-scheduled-messages {
|
|
/* Use display: grid to preserve the grid
|
|
layout when visible. */
|
|
display: grid;
|
|
}
|
|
}
|
|
|
|
.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:
|
|
var(--left-sidebar-toggle-width-offset) var(
|
|
--left-sidebar-icon-column-width
|
|
)
|
|
var(--left-sidebar-icon-content-gap) minmax(0, 1fr) minmax(
|
|
0,
|
|
max-content
|
|
)
|
|
minmax(0, max-content) 0 0;
|
|
|
|
.filter-icon {
|
|
grid-area: starting-anchor-element;
|
|
/* Use a flex container to handle
|
|
icon centering within the grid area. */
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
.left-sidebar-navigation-label {
|
|
grid-area: row-content;
|
|
padding-right: var(--left-sidebar-before-unread-count-padding);
|
|
|
|
@media screen and (resolution <= 1x) {
|
|
/* For the sake of low-resolution screens,
|
|
we'll let the actual label take 1 as a line-height
|
|
value, and allow grid to handle the alignment. */
|
|
line-height: 1;
|
|
}
|
|
}
|
|
|
|
.unread_count {
|
|
grid-area: markers-and-unreads;
|
|
/* Extra margin for unreads. */
|
|
margin-right: var(--left-sidebar-unread-offset);
|
|
|
|
&:empty {
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Low-attention unreads have no bounding box,
|
|
so their counters should be aligned on the
|
|
same baseline as the navigation label. */
|
|
.top_left_starred_messages,
|
|
.top_left_drafts,
|
|
.top_left_scheduled_messages {
|
|
.left-sidebar-navigation-label-container {
|
|
align-items: baseline;
|
|
}
|
|
|
|
.left-sidebar-navigation-label {
|
|
@media screen and (resolution <= 1x) {
|
|
/* Owing to the baseline alignment in this
|
|
area, we don't need the low-res line-height
|
|
adjustment. */
|
|
line-height: inherit;
|
|
}
|
|
}
|
|
|
|
.filter-icon {
|
|
align-self: center;
|
|
}
|
|
}
|
|
|
|
.top_left_starred_messages {
|
|
&.hide_starred_message_count {
|
|
.masked_unread_count {
|
|
display: flex;
|
|
grid-area: markers-and-unreads;
|
|
/* Extra margin for unreads. */
|
|
margin-right: var(--left-sidebar-unread-offset);
|
|
}
|
|
|
|
.unread_count {
|
|
display: none;
|
|
}
|
|
/* When starred message count is 0, we dont want to show unread_count or masked_unread_count. */
|
|
.unread_count.hide + .masked_unread_count {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
.top_left_starred_messages:hover {
|
|
&.hide_starred_message_count {
|
|
.masked_unread_count {
|
|
display: none;
|
|
}
|
|
|
|
.unread_count {
|
|
display: inline;
|
|
}
|
|
|
|
.unread_count.hide {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
.top_left_starred_messages.top-left-active-filter {
|
|
&.hide_starred_message_count {
|
|
.masked_unread_count {
|
|
display: none;
|
|
}
|
|
|
|
.unread_count {
|
|
display: inline;
|
|
}
|
|
|
|
.unread_count.hide {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
.conversation-partners {
|
|
grid-area: row-content;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.conversation-partners .status-emoji {
|
|
/* Prevent status emoji from colliding
|
|
with unread counts. */
|
|
margin-right: 3px;
|
|
/* To make status emoji look good with
|
|
multiline usernames, we need to fall
|
|
back to inline-block display here. */
|
|
display: inline-block;
|
|
vertical-align: -0.25em;
|
|
}
|
|
|
|
/* New grid definitions here. */
|
|
#views-label-container,
|
|
#hide-more-direct-messages.dm-zoomed-in,
|
|
.top_left_row,
|
|
.left-sidebar-navigation-label-container,
|
|
.dm-box,
|
|
.subscription_block,
|
|
.searching-for-more-topics {
|
|
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 icon-content-gap row-content controls markers-and-unreads ending-anchor-element ending-offset";
|
|
}
|
|
|
|
.top_left_row {
|
|
/* We stretch the items on the overall
|
|
nav row, so there's no unclickable
|
|
gaps between nav rows. */
|
|
align-items: stretch;
|
|
/* 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:
|
|
0 0 0 minmax(0, 1fr) 0 0 var(--left-sidebar-vdots-width)
|
|
0;
|
|
|
|
.sidebar-menu-icon {
|
|
grid-area: ending-anchor-element;
|
|
}
|
|
}
|
|
|
|
#direct-messages-section-header,
|
|
#streams_header,
|
|
#topics_header {
|
|
display: grid;
|
|
align-items: center;
|
|
/* This extends the general pattern of left sidebar rows, but includes a
|
|
second grid row for placing filter boxes. */
|
|
grid-template-areas:
|
|
"starting-offset starting-anchor-element icon-content-gap row-content controls markers-and-unreads ending-anchor-element ending-offset"
|
|
"filter-container filter-container filter-container filter-container filter-container filter-container filter-container filter-container";
|
|
grid-template-rows: var(--line-height-sidebar-row-prominent) minmax(
|
|
0,
|
|
max-content
|
|
);
|
|
}
|
|
|
|
.left-sidebar-filter-input-container {
|
|
grid-area: filter-container;
|
|
display: grid;
|
|
align-items: center;
|
|
grid-template:
|
|
"starting-offset filter-input ending-offset" minmax(0, max-content)
|
|
/ calc(
|
|
var(--left-sidebar-toggle-width-offset) -
|
|
var(--input-icon-starting-offset)
|
|
)
|
|
minmax(0, 1fr) var(--left-sidebar-vdots-width);
|
|
|
|
.filter-input,
|
|
.filter-topics {
|
|
grid-area: filter-input;
|
|
}
|
|
}
|
|
|
|
#views-label-container {
|
|
margin-right: var(--left-sidebar-right-margin);
|
|
grid-template-columns:
|
|
0 var(--left-sidebar-header-icon-toggle-width) 0 minmax(0, 0.5fr)
|
|
0 minmax(0, 1fr)
|
|
var(--left-sidebar-vdots-width) 0;
|
|
/* 28px at 16px/1em */
|
|
grid-template-rows: 1.75em;
|
|
cursor: pointer;
|
|
border-radius: 4px;
|
|
|
|
&:not(.remove-pointer-for-spectator):hover,
|
|
&:has(.left-sidebar-navigation-menu-icon[aria-expanded="true"]) {
|
|
background-color: var(--color-background-hover-narrow-filter);
|
|
box-shadow: inset 0 0 0 1px var(--color-shadow-sidebar-row-hover);
|
|
|
|
.left-sidebar-title,
|
|
.sidebar-heading-icon {
|
|
opacity: var(--opacity-sidebar-heading-hover);
|
|
}
|
|
}
|
|
|
|
&.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. */
|
|
.left-sidebar-title {
|
|
grid-column: row-content-start / markers-and-unreads-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 {
|
|
/* In the condensed state, we don't want to generate
|
|
auto rows, or there will be a footprint where the
|
|
expanded nav sits. */
|
|
grid-auto-rows: unset;
|
|
/* 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.top-left-active-filter {
|
|
display: grid;
|
|
/* In the absence of auto rows in the condensed state,
|
|
we set an explicit height on the active filter. */
|
|
height: var(--line-height-sidebar-row);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Remove the cursor: pointer property of Views label for the spectators. */
|
|
&.remove-pointer-for-spectator {
|
|
cursor: default;
|
|
}
|
|
|
|
#toggle-top-left-navigation-area-icon {
|
|
grid-area: starting-anchor-element;
|
|
/* Horizontally center the icon in its allotted grid area. */
|
|
justify-self: center;
|
|
}
|
|
|
|
.left-sidebar-title {
|
|
grid-area: row-content;
|
|
}
|
|
|
|
#left-sidebar-navigation-list-condensed {
|
|
margin: 0;
|
|
grid-area: markers-and-unreads;
|
|
}
|
|
|
|
.left-sidebar-navigation-menu-icon {
|
|
grid-area: ending-anchor-element;
|
|
/* Horizontally center vdots. */
|
|
justify-self: stretch;
|
|
/* Properly size vdots. */
|
|
/* 17px at 16px/1em */
|
|
font-size: 1.0625em;
|
|
/* Occupy same clickable height as
|
|
other condensed-view icons */
|
|
/* 24px at 17px/1em */
|
|
height: 1.4118em;
|
|
/* Vertically center dots with
|
|
flexbox. */
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 2px;
|
|
border-radius: 3px;
|
|
color: var(--color-vdots-visible);
|
|
|
|
&:hover {
|
|
color: var(--color-vdots-hover);
|
|
background-color: var(--color-background-sidebar-action-hover);
|
|
}
|
|
}
|
|
}
|
|
|
|
.subscription_block {
|
|
grid-template-columns:
|
|
var(--left-sidebar-toggle-width-offset) var(
|
|
--left-sidebar-icon-column-width
|
|
)
|
|
var(--left-sidebar-icon-content-gap) minmax(0, 1fr) minmax(
|
|
0,
|
|
max-content
|
|
)
|
|
minmax(0, max-content)
|
|
var(--left-sidebar-vdots-width) 0;
|
|
white-space: nowrap;
|
|
text-decoration: none;
|
|
color: inherit;
|
|
|
|
&:hover {
|
|
opacity: 1;
|
|
text-decoration: none;
|
|
color: inherit;
|
|
}
|
|
|
|
&:not(:active):focus {
|
|
text-decoration: none;
|
|
border: none;
|
|
outline: none;
|
|
color: inherit;
|
|
}
|
|
|
|
.stream-privacy {
|
|
grid-area: starting-anchor-element;
|
|
display: flex;
|
|
place-content: center center;
|
|
|
|
.zulip-icon.zulip-icon-globe {
|
|
/* 12px at 14px/1em */
|
|
font-size: 0.8571em;
|
|
}
|
|
|
|
.zulip-icon.zulip-icon-hashtag {
|
|
/* 13px at 14px/1em */
|
|
font-size: 0.9286em;
|
|
}
|
|
|
|
.zulip-icon.zulip-icon-lock {
|
|
/* 13px at 14px/1em */
|
|
font-size: 0.9286em;
|
|
}
|
|
}
|
|
|
|
.stream-name {
|
|
grid-area: row-content;
|
|
color: inherit;
|
|
|
|
&:hover {
|
|
text-decoration: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
.left-sidebar-filter-row {
|
|
display: grid;
|
|
/* The final 2px column keeps the filter box from going
|
|
to the edge of the highlighted channel box, and also
|
|
matches the right edge to the right edge of the vdots
|
|
on the channel row. (The vdots take a 2px right margin.) */
|
|
grid-template-columns:
|
|
[filter-box-start] minmax(0, 1fr)
|
|
[clear-button-start] var(--line-height-sidebar-row-prominent)
|
|
[clear-button-end filter-box-end] 2px;
|
|
grid-template-rows: [filter-box-start clear-button-start] auto [clear-button-end filter-box-end];
|
|
align-content: center;
|
|
|
|
.clear_search_button {
|
|
grid-area: clear-button;
|
|
}
|
|
}
|
|
|
|
.topic-box,
|
|
.searching-for-more-topics {
|
|
display: grid;
|
|
grid-template:
|
|
"starting-offset starting-anchor-element icon-content-gap row-content controls markers-and-unreads ending-anchor-element ending-offset" var(
|
|
--line-height-sidebar-row-prominent
|
|
)
|
|
". . . row-content . . . . " auto / 0 var(
|
|
--left-sidebar-icon-column-width
|
|
)
|
|
var(--left-sidebar-icon-content-gap)
|
|
minmax(0, 1fr) minmax(0, max-content) minmax(0, max-content)
|
|
var(--left-sidebar-vdots-width) 0;
|
|
text-decoration: none;
|
|
color: inherit;
|
|
|
|
&:hover {
|
|
opacity: 1;
|
|
text-decoration: none;
|
|
color: inherit;
|
|
}
|
|
|
|
&:not(:active):focus {
|
|
text-decoration: none;
|
|
border: none;
|
|
outline: none;
|
|
color: inherit;
|
|
}
|
|
}
|
|
|
|
.searching-for-more-topics {
|
|
margin-left: var(--left-sidebar-toggle-width-offset);
|
|
height: var(--line-height-sidebar-row-prominent);
|
|
}
|
|
|
|
.topic-box .zero_count {
|
|
display: none;
|
|
}
|
|
|
|
.sidebar-topic-name {
|
|
cursor: pointer;
|
|
grid-area: row-content;
|
|
padding: 0 var(--left-sidebar-before-unread-count-padding) 0 0;
|
|
|
|
&:hover {
|
|
color: inherit;
|
|
}
|
|
|
|
&:focus {
|
|
text-decoration: none;
|
|
}
|
|
|
|
.sidebar-topic-name-inner {
|
|
/* Clamp multi-line topics 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;
|
|
|
|
line-height: var(--line-height-sidebar-topic-inner);
|
|
margin: var(--spacing-top-bottom-sidebar-topic-inner) 0;
|
|
}
|
|
}
|
|
|
|
.sidebar-topic-action-heading {
|
|
color: var(--color-text-sidebar-action-heading);
|
|
font-size: var(--font-size-sidebar-action-heading);
|
|
font-weight: var(--font-weight-sidebar-action-heading);
|
|
font-variant: var(--font-variant-sidebar-action-heading);
|
|
font-feature-settings: var(--font-feature-settings-sidebar-action-heading);
|
|
text-transform: var(--text-transform-sidebar-action-heading);
|
|
|
|
cursor: pointer;
|
|
grid-area: row-content;
|
|
padding: 0 var(--left-sidebar-before-unread-count-padding) 0 0;
|
|
/* 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;
|
|
|
|
&:focus {
|
|
text-decoration: none;
|
|
}
|
|
|
|
&:hover {
|
|
text-decoration: none;
|
|
/* Push back against a:hover color in dark_theme.css. */
|
|
color: var(--color-text-sidebar-action-heading-hover) !important;
|
|
}
|
|
}
|
|
|
|
.filter-topics {
|
|
font-weight: initial;
|
|
}
|
|
|
|
.searching-for-more-topics img {
|
|
height: 16px;
|
|
grid-area: row-content;
|
|
}
|
|
|
|
.sidebar-topic-check {
|
|
grid-area: starting-anchor-element;
|
|
place-self: center end;
|
|
/* 15px at 14px/1em */
|
|
font-size: 1.0714em;
|
|
/* Use background to mask part of grouping bracket. */
|
|
padding-left: 3px;
|
|
/* Keep background from affecting rounded corners on
|
|
.active-sub-filter by reducing the checkbox
|
|
line-height to match its font size. */
|
|
line-height: 1;
|
|
/* As a grid item, adjust the checkmark's z-index here so
|
|
that the background color appears above the grouping
|
|
bracket's bottom line. Its value must less than
|
|
the z-index set on the #streams_header selector. */
|
|
z-index: 1;
|
|
}
|
|
|
|
.left-sidebar-controls {
|
|
grid-area: controls;
|
|
display: grid;
|
|
/* We won't know in advance how many controls a given
|
|
row has, but this allows grid to generate as many
|
|
as needed, sized to a shared icon width. */
|
|
grid-auto-columns: var(--left-sidebar-header-icon-width);
|
|
grid-template-rows: var(--line-height-sidebar-row-prominent);
|
|
place-content: stretch stretch;
|
|
margin-right: 1px;
|
|
}
|
|
|
|
.dm-markers-and-unreads,
|
|
.stream-markers-and-unreads,
|
|
.topic-markers-and-unreads {
|
|
grid-area: markers-and-unreads;
|
|
display: flex;
|
|
/* Present a uniform space between icons */
|
|
gap: 5px;
|
|
align-items: center;
|
|
justify-content: center;
|
|
/* Extra margin for unreads. */
|
|
margin-right: var(--left-sidebar-unread-offset);
|
|
|
|
&:has(.unread_count.hide) {
|
|
margin-right: 0;
|
|
}
|
|
|
|
.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;
|
|
}
|
|
}
|
|
|
|
.dm-markers-and-unreads,
|
|
.conversation-partners {
|
|
align-self: baseline;
|
|
}
|
|
|
|
.channel-new-topic-button {
|
|
/* display: flex; is set on visible channels and
|
|
channel-row hovers. */
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: var(--color-left-sidebar-heads-up-icon);
|
|
margin: 2px 0;
|
|
border-radius: 3px;
|
|
|
|
&:hover {
|
|
color: var(--color-left-sidebar-heads-up-icon-hover);
|
|
background-color: var(
|
|
--background-color-left-sidebar-heads-up-icon-hover
|
|
);
|
|
}
|
|
}
|
|
|
|
.narrow-filter:hover {
|
|
.channel-new-topic-button {
|
|
display: flex;
|
|
}
|
|
}
|
|
|
|
.bottom_left_row .sidebar-menu-icon {
|
|
grid-area: ending-anchor-element;
|
|
}
|
|
|
|
.stream-name {
|
|
white-space: nowrap;
|
|
overflow-x: hidden;
|
|
overflow-x: clip;
|
|
text-overflow: ellipsis;
|
|
padding: 0 var(--left-sidebar-before-unread-count-padding) 0 0;
|
|
}
|
|
|
|
.conversation-partners-list {
|
|
/* Clamp multi-line DMs to two lines. */
|
|
display: -webkit-box;
|
|
-webkit-box-orient: vertical;
|
|
-webkit-line-clamp: 2;
|
|
overflow: hidden;
|
|
/* Break overflowing usernames as necessary. */
|
|
overflow-wrap: break-word;
|
|
|
|
line-height: var(--line-height-sidebar-topic-inner);
|
|
margin: var(--spacing-top-bottom-sidebar-topic-inner) 0;
|
|
padding: 0 var(--left-sidebar-before-unread-count-padding) 0 0;
|
|
}
|
|
|
|
/*
|
|
All of our left sidebar handlers use absolute
|
|
positioning. We should fix that.
|
|
*/
|
|
.bottom_left_row .sidebar-menu-icon,
|
|
.top_left_row .sidebar-menu-icon {
|
|
display: none;
|
|
cursor: pointer;
|
|
/* Use a flex container to handle
|
|
icon centering within the grid area.
|
|
:hover actually sets the `display: flex`,
|
|
so it remains hidden otherwise. */
|
|
justify-content: center;
|
|
align-items: center;
|
|
text-align: center;
|
|
/* Ensure icons are vertically aligned, in
|
|
case they appear in a grid definition,
|
|
like the nav rows, that use a different
|
|
centering regime for the row. */
|
|
align-self: stretch;
|
|
border-radius: 3px;
|
|
margin: 2px 2px 2px 1px;
|
|
/* This helps horizontally align the vdots,
|
|
given the reduced margin-left above. */
|
|
padding-left: 1px;
|
|
/* Set the icon size, which will be inherited
|
|
by .zulip-icon */
|
|
/* 17px at 16px/1em */
|
|
font-size: 1.0625em;
|
|
|
|
/*
|
|
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 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: flex;
|
|
/* 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,
|
|
.app-main .column-left .left-sidebar .left_sidebar_menu_icon_visible {
|
|
/* We push against `display: none` with
|
|
`display: flex` because the sidebar vdots
|
|
all expect to be displayed as flex items
|
|
when visible. Their vertical alignment
|
|
depends on it, too. */
|
|
display: flex;
|
|
color: var(--color-vdots-visible);
|
|
|
|
&:hover {
|
|
color: var(--color-vdots-hover);
|
|
background-color: var(--color-background-sidebar-action-hover);
|
|
}
|
|
}
|
|
|
|
ul.topic-list {
|
|
line-height: var(--line-height-sidebar-row-prominent);
|
|
list-style-type: none;
|
|
font-weight: normal;
|
|
}
|
|
|
|
ul.topic-list.topic-list-has-topics::before {
|
|
content: " ";
|
|
display: block;
|
|
position: absolute;
|
|
/* 12px at 16px/1em */
|
|
top: 0.75em;
|
|
bottom: 0.75em;
|
|
left: 9px;
|
|
border: 1px solid var(--color-topic-indent-border);
|
|
border-right: 0;
|
|
border-radius: 9px 0 0 9px;
|
|
width: 6px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
ul.topic-list.topic-list-has-topics::after {
|
|
content: " ";
|
|
display: block;
|
|
position: absolute;
|
|
/* -14px at 16px/1em */
|
|
top: -0.875em;
|
|
/* 12px at 16px/1em */
|
|
bottom: 0.75em;
|
|
left: 16px;
|
|
width: 12px;
|
|
border-bottom: 1px solid var(--color-topic-indent-border);
|
|
pointer-events: none;
|
|
}
|
|
|
|
ul.topic-list:has(.show-more-topics)::after {
|
|
/* When the show all topics control is displayed,
|
|
extend the bottom bracket. */
|
|
width: 18px;
|
|
}
|
|
|
|
#stream_filters
|
|
.narrow-filter
|
|
.topic-list
|
|
.bottom_left_row:has(a.sidebar-topic-action-heading:focus-visible) {
|
|
outline: 2px solid var(--color-outline-focus);
|
|
outline-offset: -2px;
|
|
background-color: var(--color-background-hover-narrow-filter);
|
|
}
|
|
|
|
/* The grouping border should not be shown
|
|
on zoomed-in views. */
|
|
.zoom-in .topic-list.topic-list-has-topics::before,
|
|
.zoom-in .topic-list.topic-list-has-topics::after {
|
|
border: 0;
|
|
}
|
|
|
|
li.topic-list-item {
|
|
position: relative;
|
|
padding-right: 5px;
|
|
margin-left: var(--left-sidebar-toggle-width-offset);
|
|
}
|
|
|
|
.dm-box {
|
|
grid-template-columns:
|
|
var(--left-sidebar-toggle-width-offset) [action-heading-start] var(
|
|
--left-sidebar-icon-column-width
|
|
)
|
|
var(--left-sidebar-icon-content-gap) minmax(0, 1fr)
|
|
[action-heading-end] 0 minmax(0, max-content)
|
|
var(--left-sidebar-vdots-width) 0;
|
|
grid-template-rows: [action-heading-start] auto [action-heading-end];
|
|
|
|
.conversation-partners-icon {
|
|
grid-area: starting-anchor-element;
|
|
place-self: center;
|
|
|
|
&:not(.user-circle) {
|
|
place-self: start center;
|
|
}
|
|
}
|
|
|
|
.dm-name {
|
|
grid-area: action-heading;
|
|
}
|
|
|
|
.user-circle {
|
|
/* User circles are approximately 8px at 15px/1em. */
|
|
font-size: 0.5333em;
|
|
align-self: start;
|
|
}
|
|
|
|
.unread_count {
|
|
grid-area: markers-and-unreads;
|
|
/* Use flexbox to vertically center
|
|
the 12px-high text node within the
|
|
16px-high unread box. */
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
&:empty {
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Since direct-messages-sticky-header also has the `input-append`
|
|
class accompanying it. The display property of that class will
|
|
overwrite display: none if we don't have a more specific CSS
|
|
rule. It will also overwrite `display: none` even if `.zoom-out`
|
|
properties are declared after the `.input-append` properties since
|
|
the latter is more specific. */
|
|
#direct-messages-sticky-header.zoom-out,
|
|
.zoom-out {
|
|
#topics_header {
|
|
display: none;
|
|
}
|
|
|
|
.zoom-out-hide {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
#topics_header {
|
|
display: grid;
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 2;
|
|
grid-template-columns:
|
|
[topics-content-area-start] var(--left-sidebar-toggle-width-offset)
|
|
0 0 minmax(0, 1fr) 0
|
|
max-content 0 var(--left-sidebar-vdots-width)
|
|
[topics-content-area-end] var(--left-sidebar-right-margin);
|
|
grid-template-rows:
|
|
[topics-content-area-start] var(--line-height-sidebar-row-prominent)
|
|
[topics-content-area-end] 0;
|
|
padding-top: var(--left-sidebar-sections-vertical-gutter);
|
|
color: hsl(0deg 0% 43%);
|
|
background-color: var(--color-background);
|
|
/* With quiet unreads, we want the BACK TO CHANNELS
|
|
and unread count to share a common baseline. */
|
|
line-height: var(--line-height-sidebar-row);
|
|
align-items: baseline;
|
|
|
|
.show-all-streams {
|
|
grid-area: topics-content-area;
|
|
padding-left: var(--left-sidebar-toggle-width-offset);
|
|
font-size: var(--font-size-sidebar-action-heading);
|
|
font-weight: var(--font-weight-sidebar-action-heading);
|
|
font-variant: var(--font-variant-sidebar-action-heading);
|
|
text-transform: var(--text-transform-sidebar-action-heading);
|
|
color: var(--color-text-sidebar-action-heading);
|
|
text-decoration: none;
|
|
|
|
&:hover {
|
|
background-color: var(
|
|
--color-background-sidebar-action-heading-hover
|
|
);
|
|
box-shadow: inset 0 0 0 1px var(--color-shadow-sidebar-row-hover);
|
|
border-radius: 4px;
|
|
}
|
|
}
|
|
|
|
.unread_count {
|
|
grid-area: markers-and-unreads;
|
|
/* Extra margin for unreads. */
|
|
margin-right: var(--left-sidebar-unread-offset);
|
|
|
|
&:empty {
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#streams_header {
|
|
grid-template-columns:
|
|
var(--left-sidebar-toggle-width-offset) 0 0 minmax(0, 1fr) minmax(
|
|
0,
|
|
max-content
|
|
)
|
|
minmax(0, max-content) var(--left-sidebar-vdots-width)
|
|
0;
|
|
cursor: pointer;
|
|
margin: var(--left-sidebar-sections-vertical-gutter)
|
|
var(--left-sidebar-right-margin) 3px 0;
|
|
position: sticky;
|
|
/* Keep sticky within SimpleBar context. The -0.25px
|
|
offset ensures that no gap is present between the
|
|
direct-messages-section-header and the streams-header */
|
|
top: -0.25px;
|
|
z-index: 2;
|
|
background-color: var(--color-background);
|
|
|
|
&.showing-stream-search-section {
|
|
/* Open up the stream-search rows and maintain
|
|
space with the streams list below. */
|
|
padding-bottom: var(--left-sidebar-sections-vertical-gutter);
|
|
row-gap: 3px;
|
|
|
|
/* When the search section is showing, switch
|
|
off the hover effects on the row. */
|
|
&:hover {
|
|
background-color: var(--color-background);
|
|
box-shadow: unset;
|
|
}
|
|
}
|
|
|
|
.left-sidebar-title {
|
|
grid-area: row-content;
|
|
}
|
|
|
|
.heading-markers-and-unreads {
|
|
grid-area: markers-and-unreads;
|
|
height: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
grid-gap: 5px;
|
|
/* Extra margin for unreads. */
|
|
margin-right: var(--left-sidebar-unread-offset);
|
|
|
|
&:has(.unread_count:empty) {
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
|
|
#filter_streams_tooltip {
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
grid-row: 1 / 1;
|
|
margin: 2px 0;
|
|
|
|
@media (hover: none) {
|
|
display: flex;
|
|
}
|
|
}
|
|
|
|
#add_streams_tooltip {
|
|
grid-row: 1 / 1;
|
|
margin: 2px 0;
|
|
}
|
|
|
|
#streams_inline_icon {
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
/* Ensure the clickable area grows to
|
|
the height of the controls grid. */
|
|
height: 100%;
|
|
|
|
@media (hover: none) {
|
|
display: flex;
|
|
}
|
|
}
|
|
|
|
&:hover,
|
|
&.showing-streams-popover {
|
|
/* We only set the border radius on the hover/popover states,
|
|
so as to prevent the background on highlighted channels
|
|
from bleeding through. */
|
|
border-radius: 4px;
|
|
background-color: var(--color-background-opaque-hover-narrow-filter);
|
|
box-shadow: inset 0 0 0 1px var(--color-shadow-sidebar-row-hover);
|
|
|
|
.left-sidebar-title,
|
|
.sidebar-heading-icon {
|
|
opacity: var(--opacity-sidebar-heading-hover);
|
|
}
|
|
|
|
#filter_streams_tooltip,
|
|
#streams_inline_icon {
|
|
display: flex;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Prepare an adjusted grid for the logged-out state,
|
|
one that reassigns the vdots space to markers and
|
|
controls. */
|
|
.spectator-view #streams_header {
|
|
grid-template-columns:
|
|
var(--left-sidebar-toggle-width-offset) 0 0 minmax(0, 1fr) 0
|
|
minmax(var(--left-sidebar-vdots-width), max-content) 0 0;
|
|
margin-right: var(--left-sidebar-right-margin);
|
|
|
|
/* With markers and controls now sized the same
|
|
as the ordinary vdots area (but allowed to grow,
|
|
care of `minmax(30px, max-content)`, should
|
|
additional logged-out icons be added in the
|
|
future), let's center the icon in that area,
|
|
just like vdots would be. */
|
|
.heading-markers-and-unreads {
|
|
justify-content: center;
|
|
}
|
|
}
|
|
|
|
.streams_subheader {
|
|
/* 14px at 16px/1em */
|
|
font-size: 0.875em;
|
|
font-weight: normal;
|
|
/* 16px line-height at 0.8em (11.2px at 14px legacy em) */
|
|
line-height: 1.4286em;
|
|
letter-spacing: 0.04em;
|
|
padding-left: var(--left-sidebar-toggle-width-offset);
|
|
cursor: pointer;
|
|
text-align: center;
|
|
margin-right: var(--left-sidebar-right-margin);
|
|
|
|
& .streams-subheader-wrapper {
|
|
display: flex;
|
|
flex-direction: row;
|
|
width: 100%;
|
|
left: 0.5em;
|
|
right: 0.5em;
|
|
color: var(--color-text-sidebar-base);
|
|
}
|
|
|
|
& .streams-subheader-wrapper::before,
|
|
.streams-subheader-wrapper::after {
|
|
content: " ";
|
|
flex: 1 1;
|
|
vertical-align: middle;
|
|
margin: auto;
|
|
border-top: 1px solid var(--color-border-sidebar-subheader);
|
|
}
|
|
|
|
& .streams-subheader-wrapper::before {
|
|
margin-right: 0.2em;
|
|
}
|
|
|
|
& .streams-subheader-wrapper::after {
|
|
margin-left: 0.2em;
|
|
}
|
|
|
|
.streams-subheader-name {
|
|
opacity: 0.4;
|
|
}
|
|
}
|
|
|
|
.zero_count {
|
|
visibility: hidden;
|
|
}
|
|
|
|
.zero-topic-unreads.show-more-topics .topic-box {
|
|
margin-right: 30px;
|
|
}
|
|
|
|
.zoom-in {
|
|
.narrow-filter > .bottom_left_row {
|
|
position: sticky;
|
|
/* We subtract a quarter pixel of space to correct
|
|
for possible bleedthrough under certain viewing
|
|
conditions (e.g., external monitors.) This same
|
|
technique is used on #streams_header. */
|
|
top: calc(
|
|
var(--left-sidebar-sections-vertical-gutter) +
|
|
var(--line-height-sidebar-row-prominent) - 0.25px
|
|
);
|
|
z-index: 2;
|
|
padding-bottom: 1px;
|
|
background-color: var(--color-background);
|
|
|
|
&:hover {
|
|
/* Prevent hover styles set on other rows. */
|
|
box-shadow: none;
|
|
background-color: var(--color-background);
|
|
}
|
|
}
|
|
|
|
#streams_header,
|
|
#subscribe-to-more-streams,
|
|
#login-to-more-streams,
|
|
.show-more-topics {
|
|
display: none;
|
|
}
|
|
|
|
&.direct-messages-container ul.dm-list {
|
|
margin-bottom: var(--left-sidebar-bottom-scrolling-buffer);
|
|
}
|
|
|
|
.direct-messages-search-section {
|
|
grid-column: filter-container;
|
|
margin: 5px 0;
|
|
}
|
|
|
|
.zoom-in-hide {
|
|
display: none;
|
|
}
|
|
|
|
.zoom-in-sticky {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 1;
|
|
}
|
|
}
|