mirror of https://github.com/zulip/zulip.git
1463 lines
37 KiB
CSS
1463 lines
37 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 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;
|
|
}
|
|
}
|
|
|
|
.left-sidebar-title {
|
|
color: var(--color-text-sidebar-heading);
|
|
font-size: inherit;
|
|
font-weight: normal;
|
|
display: inline;
|
|
/* 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;
|
|
}
|
|
|
|
.sidebar-topic-check,
|
|
.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 {
|
|
opacity: 0.5;
|
|
|
|
&:hover {
|
|
opacity: 1;
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
|
|
.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: hidden auto;
|
|
position: relative;
|
|
z-index: 0;
|
|
width: 100%;
|
|
|
|
.direct-messages-container {
|
|
/* TODO: Clean up this value and the
|
|
analogous one on #stream-filters;
|
|
this could be done alongside the
|
|
--left-sidebar-collapse-widget-gutter
|
|
cleanup so that all of the left sidebar
|
|
space is better, more uniformly handled.
|
|
That will be an essential pre-condition
|
|
for a resizable left sidebar. */
|
|
margin-right: 12px;
|
|
margin-left: 0;
|
|
}
|
|
}
|
|
|
|
.direct-messages-container {
|
|
/* Properly offset all the grid rows
|
|
in the DM section. */
|
|
margin-right: 12px;
|
|
|
|
#private_messages_section_header {
|
|
grid-template-columns: 0 15px minmax(0, 1fr) max-content 30px 0;
|
|
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;
|
|
white-space: nowrap;
|
|
|
|
#toggle_private_messages_section_icon {
|
|
grid-area: starting-anchor-element;
|
|
}
|
|
|
|
.left-sidebar-title {
|
|
grid-area: row-content;
|
|
}
|
|
|
|
.heading-markers-and-controls {
|
|
grid-area: markers-and-controls;
|
|
display: flex;
|
|
gap: 5px;
|
|
align-items: center;
|
|
}
|
|
|
|
#show_all_private_messages {
|
|
width: var(--left-sidebar-header-icon-width);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
opacity: 0.7;
|
|
text-decoration: none;
|
|
color: inherit;
|
|
|
|
&:hover {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
& ul.dm-list {
|
|
list-style-type: none;
|
|
font-weight: 400;
|
|
margin-left: 0;
|
|
margin-bottom: 0;
|
|
|
|
& span.fa-group {
|
|
font-size: 90%;
|
|
}
|
|
|
|
& li.dm-list-item {
|
|
& a {
|
|
text-decoration: none;
|
|
color: inherit;
|
|
}
|
|
|
|
.fa-group,
|
|
.zulip-icon {
|
|
opacity: 0.7;
|
|
}
|
|
}
|
|
|
|
& li#show-more-direct-messages {
|
|
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;
|
|
|
|
& a {
|
|
font-size: 12px;
|
|
}
|
|
|
|
.unread_count {
|
|
margin-top: 2px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#toggle_private_messages_section_icon,
|
|
#toggle-top-left-navigation-area-icon {
|
|
opacity: 0.7;
|
|
|
|
&.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,
|
|
#direct-messages-list,
|
|
#hide-more-direct-messages {
|
|
background-color: hsl(202deg 56% 91%);
|
|
}
|
|
|
|
#private_messages_section {
|
|
border-radius: 4px 4px 0 0;
|
|
}
|
|
|
|
#direct-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);
|
|
}
|
|
}
|
|
|
|
.top_left_row,
|
|
.bottom_left_row {
|
|
/* Ensure a border radius on any interactive
|
|
state that might show a highlight. */
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
#login-link-container {
|
|
color: var(--color-text-url);
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
&:hover {
|
|
cursor: pointer;
|
|
color: var(--color-text-url-hover);
|
|
|
|
&.login_button .login-text {
|
|
color: var(--color-text-url-hover);
|
|
text-decoration: underline;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
.zulip-icon-follow {
|
|
opacity: 0.6;
|
|
}
|
|
|
|
& 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;
|
|
/* 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-hover-narrow-filter);
|
|
|
|
.unread_count {
|
|
top: -6px;
|
|
right: -6px;
|
|
background: var(--color-background-unread-counter-no-alpha);
|
|
}
|
|
}
|
|
|
|
&: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;
|
|
/* Enlarge icons slightly in condensed views. */
|
|
font-size: 15px;
|
|
color: var(--color-left-sidebar-navigation-icon);
|
|
}
|
|
}
|
|
|
|
#left-sidebar-navigation-list {
|
|
margin-bottom: $sections_vertical_gutter;
|
|
/* We display this as a grid only to control
|
|
the order of home views, using a single
|
|
named grid area. */
|
|
display: grid;
|
|
grid-template-areas: "selected-home-view";
|
|
|
|
.left-sidebar-navigation-label-container {
|
|
.left-sidebar-navigation-label {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
}
|
|
}
|
|
|
|
.selected-home-view {
|
|
/* This bumps the selected view to the
|
|
top of the grid (expanded list).
|
|
Others items will auto place in the
|
|
remaining auto-generated grid rows. */
|
|
grid-area: selected-home-view;
|
|
/* The condensed view is a flexbox, so
|
|
here we'll use a negative order to
|
|
bump the selected home view to the
|
|
start of the flexbox (lefthand side). */
|
|
order: -1;
|
|
}
|
|
|
|
.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);
|
|
}
|
|
|
|
/* Don't show unread counts on views... */
|
|
.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;
|
|
}
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
|
|
.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;
|
|
/* 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: $before_unread_count_padding;
|
|
}
|
|
|
|
.unread_count {
|
|
grid-area: markers-and-controls;
|
|
}
|
|
}
|
|
|
|
.conversation-partners {
|
|
grid-area: row-content;
|
|
/* Set an 18px line-height to better vertically
|
|
center user circles and icons (both of which
|
|
have even heights). */
|
|
line-height: 18px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
/* Use an inline grid to provide a modern layout
|
|
for status emoji in DM rows, while preserving
|
|
the expected ellipsis behavior on long usernames
|
|
or large DM groups.
|
|
The 16px-tall emoji will also align well
|
|
vertically with the 18px line-height here. */
|
|
display: inline-grid;
|
|
/* Provide a two-column grid, sized to accommodate
|
|
the content of the conversation list and status
|
|
emoji, if any. */
|
|
grid-template-columns: repeat(2, minmax(0, max-content));
|
|
align-items: center;
|
|
}
|
|
|
|
.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,
|
|
.dm-box,
|
|
.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";
|
|
}
|
|
|
|
#private_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. This pattern keeps the box
|
|
aligned with the text content in `row-content` and includes the
|
|
`ending-anchor-element` space.
|
|
|
|
There is currently no filter box on DM rows, but we can prepare for
|
|
that now by having it share this grid template. Its row and column
|
|
definitions have the final say about dimensions and placement. */
|
|
grid-template-areas:
|
|
"starting-offset starting-anchor-element row-content markers-and-controls ending-anchor-element ending-offset"
|
|
". . filter-box filter-box filter-box . ";
|
|
}
|
|
|
|
#views-label-container {
|
|
grid-template-columns:
|
|
0 15px minmax(0, 0.5fr) minmax(0, 1fr)
|
|
30px 12px;
|
|
/* 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. */
|
|
.left-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;
|
|
}
|
|
|
|
.left-sidebar-title {
|
|
grid-area: row-content;
|
|
}
|
|
|
|
#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-name {
|
|
cursor: pointer;
|
|
grid-area: row-content;
|
|
padding: 1px $before_unread_count_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;
|
|
}
|
|
}
|
|
|
|
.topic-box .zero_count {
|
|
display: none;
|
|
}
|
|
|
|
.sidebar-topic-check {
|
|
grid-area: starting-anchor-element;
|
|
font-size: 15px;
|
|
height: 20px;
|
|
}
|
|
|
|
.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 .sidebar-menu-icon {
|
|
grid-area: ending-anchor-element;
|
|
}
|
|
|
|
.conversation-partners-list,
|
|
.stream-name {
|
|
white-space: nowrap;
|
|
overflow-x: hidden;
|
|
overflow-x: clip;
|
|
text-overflow: ellipsis;
|
|
padding: 1px $before_unread_count_padding 1px 0;
|
|
}
|
|
|
|
.conversation-partners-list {
|
|
/* TODO: See about consolidating or re-expressing
|
|
.stream-name spacing so as to not require
|
|
padding there, either. */
|
|
padding: 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;
|
|
width: 100%;
|
|
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;
|
|
text-align: center;
|
|
/* Set the icon size, which will be inherited
|
|
by .zulip-icon */
|
|
font-size: 17px;
|
|
|
|
/*
|
|
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);
|
|
|
|
/*
|
|
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.
|
|
*/
|
|
.topic-sidebar-menu-icon {
|
|
/* 0.9em, but with a pixel value because the
|
|
ordinary 17px vdots size is not inherited
|
|
here, so we can't express an em-value
|
|
directly. Pixels are easier to reason
|
|
about with icons, anyway. */
|
|
font-size: 15.3px;
|
|
}
|
|
|
|
ul.topic-list {
|
|
list-style-type: none;
|
|
font-weight: normal;
|
|
}
|
|
|
|
li.topic-list-item {
|
|
position: relative;
|
|
padding-right: 5px;
|
|
}
|
|
|
|
.dm-box {
|
|
grid-template-columns: 7px 22px minmax(0, 1fr) minmax(0, max-content) 30px 0;
|
|
/* This padding maintains a 22px height on DM rows. */
|
|
padding: 2px 0;
|
|
|
|
.conversation-partners-icon {
|
|
grid-area: starting-anchor-element;
|
|
place-self: center;
|
|
}
|
|
|
|
.dm-name {
|
|
grid-area: row-content;
|
|
}
|
|
|
|
.user_circle {
|
|
width: 8px;
|
|
height: 8px;
|
|
/* TODO: Remove these after right-sidebar
|
|
row rewrites. */
|
|
float: none;
|
|
position: static;
|
|
}
|
|
|
|
.zulip-icon.zulip-icon-bot {
|
|
font-size: 90%; /* Reduce the bulkiness of this icon */
|
|
}
|
|
|
|
.unread_count {
|
|
grid-area: markers-and-controls;
|
|
/* TODO: This is an alternative method
|
|
for presenting a 16px-tall unread
|
|
counter, regardless of context. This
|
|
method could be used app-wide once
|
|
all of the layout methods for presenting
|
|
unreads have been modernized.
|
|
|
|
Set the line-height to match the
|
|
font-size, so that the numerals sit in
|
|
a 12px box. */
|
|
line-height: 12px;
|
|
/* Use flexbox to vertically center
|
|
the 12px-high text node within the
|
|
16px-high unread box. */
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
}
|
|
|
|
.zoom-out {
|
|
#topics_header {
|
|
display: none;
|
|
}
|
|
|
|
.zoom-out-hide {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
#topics_header {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 2;
|
|
grid-template-columns: 0 0 minmax(0, 1fr) max-content 0 42px;
|
|
grid-template-rows: 24px;
|
|
padding-top: $sections_vertical_gutter;
|
|
color: hsl(0deg 0% 43%);
|
|
background-color: var(--color-background);
|
|
|
|
.show-all-streams {
|
|
grid-area: row-content;
|
|
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;
|
|
}
|
|
}
|
|
|
|
.unread_count {
|
|
grid-area: markers-and-controls;
|
|
}
|
|
}
|
|
|
|
#streams_header {
|
|
grid-template-columns: 0 0 minmax(0, 1fr) minmax(17px, max-content) 30px 12px;
|
|
/* Keep the stream-search area rows collapsed. */
|
|
grid-template-rows: 24px 0 0;
|
|
cursor: pointer;
|
|
padding: $sections_vertical_gutter 0 3px calc($far_left_gutter_size + 2px);
|
|
position: sticky;
|
|
/* Keep sticky within SimpleBar context. */
|
|
top: 0;
|
|
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. */
|
|
z-index: 1;
|
|
|
|
&.showing-stream-search-section {
|
|
/* Open up the stream-search rows. The 10px
|
|
row maintains space with the streams list
|
|
below. */
|
|
grid-template-rows: 24px 28px 10px;
|
|
}
|
|
|
|
.left-sidebar-title {
|
|
grid-area: row-content;
|
|
}
|
|
|
|
.heading-markers-and-controls {
|
|
grid-area: markers-and-controls;
|
|
height: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
grid-gap: 5px;
|
|
}
|
|
|
|
#filter_streams_tooltip {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: var(--left-sidebar-header-icon-width);
|
|
}
|
|
|
|
#add_streams_tooltip {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: var(--left-sidebar-header-icon-width);
|
|
}
|
|
|
|
.input-append {
|
|
grid-area: filter-box;
|
|
display: flex;
|
|
justify-content: stretch;
|
|
/* Set an even line-height for better
|
|
vertical centering. */
|
|
line-height: 20px;
|
|
white-space: nowrap;
|
|
|
|
& input {
|
|
/* Use the border-box model so flex
|
|
can do its thing despite whatever
|
|
padding and border we specify. */
|
|
box-sizing: border-box;
|
|
flex: 1 0 100%;
|
|
/* Match the input height exactly
|
|
with the row height for a perfect
|
|
fit and better vertical alignment. */
|
|
height: 28px;
|
|
/* Pad the entire clear-button area,
|
|
so that input text does not bleed
|
|
into there. */
|
|
padding-right: 30px;
|
|
}
|
|
|
|
.clear_search_button {
|
|
/* Use the border-box model so flex
|
|
can do its thing despite whatever
|
|
padding and border we specify. */
|
|
box-sizing: border-box;
|
|
/* Clear inherited positioning. */
|
|
position: static;
|
|
/* We're going to use flexbox, not
|
|
positioning, to get the clear button
|
|
over top of the input. This -30px
|
|
margin accomplishes that, in tandem
|
|
with the 30px width of this element,
|
|
which is shared with the ending
|
|
anchor element in left sidebar header
|
|
rows. */
|
|
width: 30px;
|
|
margin-left: -30px;
|
|
/* Flexbox respects z-index; this just
|
|
ensures the button remains over top
|
|
of the input. */
|
|
z-index: 1;
|
|
/* Make the button itself a flex container,
|
|
so we can perfectly center the X icon. */
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
/* Flexbox will pull the element open
|
|
to make a generous clickable area. */
|
|
padding: 0;
|
|
}
|
|
}
|
|
|
|
&.hide_unread_counts {
|
|
.unread_count,
|
|
.unread_count.hide,
|
|
.masked_unread_count {
|
|
display: none;
|
|
}
|
|
|
|
/* When an empty unread count is hidden,
|
|
hide the masked unread count, too. */
|
|
.unread_count.hide + .masked_unread_count {
|
|
display: none;
|
|
}
|
|
|
|
.masked_unread_count {
|
|
display: block;
|
|
/* Hold space enough so single-digit
|
|
unreads don't shift on hover. */
|
|
margin: 0 3px;
|
|
}
|
|
|
|
&:hover {
|
|
.unread_count {
|
|
display: block;
|
|
}
|
|
|
|
.hide,
|
|
.masked_unread_count {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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: 0 0 minmax(0, 1fr) minmax(30px, max-content) 0 12px;
|
|
|
|
/* 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-controls {
|
|
justify-content: center;
|
|
}
|
|
}
|
|
|
|
.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 {
|
|
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);
|
|
}
|
|
|
|
#streams_header,
|
|
#subscribe-to-more-streams,
|
|
.show-more-topics {
|
|
display: none;
|
|
}
|
|
|
|
&.direct-messages-container ul.dm-list {
|
|
margin-bottom: $bottom_scrolling_buffer;
|
|
}
|
|
|
|
#more_private_messages_sidebar_title {
|
|
display: inline;
|
|
}
|
|
|
|
#hide-more-direct-messages {
|
|
display: block;
|
|
text-decoration: none;
|
|
color: inherit;
|
|
font-size: 12px;
|
|
|
|
& span {
|
|
display: block;
|
|
/* TODO: Rewrite the show-more and show-less
|
|
buttons as grids alongside the left sidebar
|
|
header rewrites. The 12px left padding here
|
|
aligns the "back to channels" text with the
|
|
DIRECT MESSAGES heading above, which itself
|
|
is offset -3 px to the left, but reserves
|
|
15px for the arrow marker. 15px - 3px = 12px. */
|
|
padding: 2px 0 2px 12px;
|
|
}
|
|
|
|
&: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;
|
|
}
|
|
}
|