snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
This commit is contained in:
957
web/styles/inbox.css
Normal file
957
web/styles/inbox.css
Normal file
@@ -0,0 +1,957 @@
|
||||
.inbox-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--color-background-inbox);
|
||||
padding: 0;
|
||||
min-height: 100vh;
|
||||
|
||||
#inbox-pane {
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: var(--navbar-fixed-height) 25px 0;
|
||||
|
||||
a {
|
||||
color: var(--color-text-message-header);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.unread_count {
|
||||
opacity: 1;
|
||||
outline: 0 solid var(--color-background-unread-counter);
|
||||
}
|
||||
|
||||
.search_group {
|
||||
position: sticky;
|
||||
top: var(--navbar-fixed-height);
|
||||
background: var(--color-background-inbox);
|
||||
display: flex;
|
||||
/* This padding-top value aligns the inbox filters
|
||||
with the filters in the left and right sidebars. */
|
||||
padding: 10px 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.button-inbox-selected {
|
||||
background-color: var(--color-background-button-inbox-selected);
|
||||
}
|
||||
|
||||
#inbox-filters {
|
||||
.inbox-search-wrapper {
|
||||
flex-grow: 1;
|
||||
max-width: var(--width-inbox-search);
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-empty-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#inbox-loading-indicator {
|
||||
margin-top: 20px;
|
||||
margin-bottom: var(--max-unmaximized-compose-height);
|
||||
|
||||
.searching-for-more-topics {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#inbox-list {
|
||||
overflow: hidden;
|
||||
/* search box left border (1px) + search box right border (1px)
|
||||
+ dropdown left border (1px) + dropdown right border (1px) = 4px at 16px em */
|
||||
max-width: calc(
|
||||
var(--width-inbox-search) +
|
||||
var(--width-inbox-filters-dropdown) + 0.25em
|
||||
);
|
||||
|
||||
.inbox-channel-topic-list {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.inbox-focus-border {
|
||||
display: flex;
|
||||
min-height: 1.875em; /* 30px at 16px em */
|
||||
/* Holds the horizontal layout that the removed
|
||||
`border: 2px solid transparent` was reserving;
|
||||
`.inbox-row`'s outline-based focus doesn't reserve
|
||||
space. Vertical padding omitted so the 30px icon
|
||||
wrappers fit in the 30px row height. */
|
||||
padding-inline: 0.125em; /* 2px at 16px/1em */
|
||||
box-sizing: border-box;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.inbox-header {
|
||||
user-select: none;
|
||||
display: block;
|
||||
height: 1.875em; /* 30px at 16px em */
|
||||
|
||||
.inbox-focus-border {
|
||||
height: 1.875em; /* 30px at 16px em */
|
||||
}
|
||||
|
||||
.inbox-left-part {
|
||||
grid-template:
|
||||
auto / minmax(auto, min-content)
|
||||
auto min-content min-content;
|
||||
grid-template-areas: "header_name collapse_button unread_mention_info unread_count";
|
||||
}
|
||||
|
||||
.inbox-header-name {
|
||||
grid-area: header_name;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
outline: 0;
|
||||
cursor: pointer;
|
||||
|
||||
.inbox-header-name-text {
|
||||
margin: 0;
|
||||
padding: 1px 0;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.collapsible-button {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fa-lock {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.stream-privacy.filter-icon {
|
||||
/* 0 5px at 16px/1em */
|
||||
padding: 0 0.3125em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.zulip-icon-user {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.collapsible-button {
|
||||
grid-area: collapse_button;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.zulip-icon-chevron-down {
|
||||
/* We are using very specific vertical padding here
|
||||
* to avoid the inbox row grid overflow. */
|
||||
padding: 0.125em 0.25em; /* 2px 4px at 16px em */
|
||||
vertical-align: top;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.user-circle {
|
||||
/* 8.5328px at 16px/1em */
|
||||
font-size: 0.5333em;
|
||||
/* TODO: Refactor inbox rows to use grid, to avoid the
|
||||
min-width here that holds the other rows to similar
|
||||
columns. */
|
||||
/* 16px at 8.5328px/1em */
|
||||
min-width: 1.8751em;
|
||||
top: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.zulip-icon-bot,
|
||||
.conversation-partners-icon {
|
||||
opacity: 0.7;
|
||||
/* Required to align DM fullnames in user circle icon */
|
||||
/* 2px at 16px / 1em */
|
||||
margin-left: 0.125em;
|
||||
}
|
||||
|
||||
.user_block .zulip-icon {
|
||||
/* 0 5px at 16px/1em */
|
||||
padding: 0 0.3125em;
|
||||
|
||||
&.user-circle {
|
||||
/* 5px at 16px / ~ 0.5em */
|
||||
padding: 0 0.586em;
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-row {
|
||||
user-select: none;
|
||||
display: block;
|
||||
background-color: var(--color-background-inbox-row);
|
||||
|
||||
&:hover {
|
||||
background: var(--color-background-inbox-row-hover);
|
||||
}
|
||||
|
||||
.inbox-left-part {
|
||||
grid-template:
|
||||
auto / min-content minmax(0, 1fr)
|
||||
min-content min-content;
|
||||
grid-template-areas: "match_topic_and_dm_start recipient_info unread_mention_info unread_count";
|
||||
}
|
||||
|
||||
.inbox-topic-container .user-circle {
|
||||
grid-area: match_topic_and_dm_start;
|
||||
}
|
||||
|
||||
.recipients_info,
|
||||
.inbox-topic-name {
|
||||
grid-area: recipient_info;
|
||||
}
|
||||
}
|
||||
|
||||
.channel-visibility-policy-indicator,
|
||||
.visibility-policy-indicator,
|
||||
.inbox-action-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
/* Row-tall, row-square click area so there's
|
||||
room for the focus ring around the inner icon
|
||||
without clipping against the row's right edge.
|
||||
Centering the icon (vs. anchoring to an edge)
|
||||
keeps the focus ring symmetric around it. */
|
||||
width: 1.875em; /* 30px — matches row height */
|
||||
height: 1.875em; /* 30px — matches row height */
|
||||
/* Whole 30×30 hit area is clickable; the inner
|
||||
icon itself only spans ~16×16. Without this,
|
||||
mouse hovers at the top/bottom fall back to the
|
||||
default arrow cursor. */
|
||||
cursor: pointer;
|
||||
|
||||
& > i,
|
||||
& > .zulip-icon,
|
||||
& > .recipient_bar_icon {
|
||||
/* Zero out per-icon padding; the outer button
|
||||
is the click area and the focus ring draws
|
||||
outside the icon via `outline-offset`.
|
||||
Overrides `.recipient_bar_icon`'s 6px side
|
||||
padding from message_header.css. */
|
||||
padding: 0;
|
||||
border-radius: 0.3125em; /* 5px at 16px/1em */
|
||||
}
|
||||
}
|
||||
|
||||
.channel-visibility-policy-indicator,
|
||||
.visibility-policy-indicator {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
/* Normalize the inner icon's opacity to 1 so the outer
|
||||
wrapper is the single source of truth for opacity.
|
||||
Overrides `.recipient_bar_icon`'s 0.2 idle / 0.4
|
||||
hover from message_header.css for every marker
|
||||
wrapper — follow, mute, unmute, and the inherit
|
||||
(default) placeholder that becomes visible on row
|
||||
hover. */
|
||||
.channel-visibility-policy-indicator > .recipient_bar_icon,
|
||||
.visibility-policy-indicator > .recipient_bar_icon {
|
||||
opacity: 1;
|
||||
|
||||
/* Beat `.recipient_bar_icon:hover`'s !important. */
|
||||
&:hover {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Explicit topic/channel state markers are secondary
|
||||
information: visible at a glance, quieter than primary
|
||||
content. 0.45 is the lowest opacity that meets WCAG
|
||||
1.4.11's 3:1 non-text contrast against both the light
|
||||
(~3.4:1) and dark (~3.9:1) inbox row backgrounds. */
|
||||
.channel-visibility-policy-indicator,
|
||||
.visibility-policy-indicator:not(
|
||||
.inbox-row-visibility-policy-inherit
|
||||
) {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
/* Row-level interaction tiers for the icon-style wrapper
|
||||
types: action menu, channel-level marker, topic-level
|
||||
marker. The inherit subclass is reached via the
|
||||
topic-level marker since `.inbox-row-visibility-policy-
|
||||
inherit` is also a `.visibility-policy-indicator`. */
|
||||
.inbox-row,
|
||||
.inbox-header {
|
||||
/* Mouse hover reveals/lifts wrappers to 0.45,
|
||||
matching the explicit-marker idle tier. */
|
||||
&:hover {
|
||||
:is(
|
||||
.inbox-action-button,
|
||||
.channel-visibility-policy-indicator,
|
||||
.visibility-policy-indicator
|
||||
) {
|
||||
opacity: 0.45;
|
||||
}
|
||||
}
|
||||
|
||||
/* Keyboard selection alone (row focused but not
|
||||
mouse-hovered) reveals only the usually-hidden
|
||||
action buttons at a much quieter 0.2. Explicit
|
||||
state markers stay at their 0.45 idle — only the
|
||||
tertiary reveal needs this extra-quiet step. The
|
||||
`:not(:focus-visible)` exclusion ensures that when
|
||||
the button itself has keyboard focus (via arrow-
|
||||
right into the column), its own `:focus-visible`
|
||||
rule sets the direct-interaction tier instead. */
|
||||
&:focus-within:not(:focus, :hover) {
|
||||
:is(
|
||||
.inbox-action-button,
|
||||
.inbox-row-visibility-policy-inherit
|
||||
):not(:focus-visible) {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus-visible:not(:hover) {
|
||||
:is(
|
||||
.inbox-action-button,
|
||||
.inbox-row-visibility-policy-inherit
|
||||
) {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Direct hover on a wrapper lifts to 0.7. Compound
|
||||
selector beats the row-wide reveal on specificity. */
|
||||
&:hover
|
||||
:is(
|
||||
.inbox-action-button,
|
||||
.channel-visibility-policy-indicator,
|
||||
.visibility-policy-indicator
|
||||
):hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Wrapper keyboard focus = full opacity so the focus
|
||||
ring renders at full blue saturation (WCAG 1.4.11
|
||||
3:1 contrast). The inner icon dims to 0.7
|
||||
separately via the rule under `&:focus-visible > i`
|
||||
above. */
|
||||
&:focus-within
|
||||
:is(
|
||||
.inbox-action-button,
|
||||
.channel-visibility-policy-indicator,
|
||||
.visibility-policy-indicator
|
||||
):focus-visible {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.unread-count-focus-outline {
|
||||
/* Because the inbox view font-size will
|
||||
never be smaller than the em-equivalent
|
||||
of 15px, we restate the base font-size
|
||||
here so that unreads match others in
|
||||
the UI at legacy size (14px). */
|
||||
font-size: var(--base-font-size-px);
|
||||
grid-area: unread_count;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 3px;
|
||||
padding: 0 5px;
|
||||
/* Stretch to the row to keep unread
|
||||
count from affecting overall row
|
||||
size as test scales up. */
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
/* Channels, topics, and direct messages mark their unread
|
||||
messages as read when their count is clicked. Folder
|
||||
headers (channel folders and the direct messages section)
|
||||
only show a combined count for everything inside them, so
|
||||
they don't get the clickable affordance. */
|
||||
:is(.inbox-row, .inbox-header:not(.inbox-folder))
|
||||
.unread-count-focus-outline {
|
||||
/* Whole 30×stretched hit area is clickable; surface
|
||||
the same pointer cursor users had on the smaller
|
||||
badge before the click target was expanded. */
|
||||
cursor: pointer;
|
||||
|
||||
/* Forward the badge's hover outline to the wrapper:
|
||||
the click handler now lives on the wrapper, so
|
||||
hovering anywhere in the wrapper (not just the
|
||||
small inner badge) should preview the click
|
||||
affordance. */
|
||||
&:hover .unread_count {
|
||||
outline-width: var(--focus-ring-width-in-views);
|
||||
}
|
||||
}
|
||||
|
||||
.unread_mention_info {
|
||||
grid-area: unread_mention_info;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.stream-privacy {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 4px;
|
||||
margin-left: 17px;
|
||||
|
||||
.zulip-icon {
|
||||
line-height: 0.875em; /* 14px at 16px em */
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-topic-name {
|
||||
/* 16px channel icon width + 10px padding */
|
||||
padding-left: 1.625em; /* 26x at 16px em */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
& a {
|
||||
padding: 1px 0;
|
||||
white-space: pre;
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-left-part-wrapper {
|
||||
display: flex;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.inbox-left-part {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.inbox-group-or-bot-dm {
|
||||
position: relative;
|
||||
left: -3px;
|
||||
|
||||
/* We don't display status emoji in group DMs,
|
||||
so prepare an ordinary inline layout... */
|
||||
.user-status-microlayout {
|
||||
display: inline;
|
||||
white-space: collapse;
|
||||
}
|
||||
/* ...and hide the status emoji. */
|
||||
.status-emoji {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.recipients_info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
column-gap: 10px;
|
||||
grid-area: recipient_info;
|
||||
|
||||
.user_block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#inbox-collapsed-note {
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
max-width: calc(
|
||||
var(--width-inbox-search) +
|
||||
var(--width-inbox-filters-dropdown) + 0.25em
|
||||
);
|
||||
|
||||
.inbox-collapsed-note-and-button-wrapper {
|
||||
margin-top: 3px;
|
||||
padding-left: 8px;
|
||||
|
||||
.inbox-collapsed-note-span {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#inbox-expand-all-button {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-right-part-wrapper {
|
||||
flex-grow: 1;
|
||||
|
||||
.inbox-right-part {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-grow: 1;
|
||||
|
||||
> .inbox-action-button:first-child {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-row-visibility-policy-inherit {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Stickiness: while a marker or action button has its popover
|
||||
open, keep it in the direct-interaction tier (0.7) so the
|
||||
user can see which element the open menu belongs to.
|
||||
Substring match on `*-popover-visible` covers every class
|
||||
the popover JS toggles — `topic-popover-visible` (added by
|
||||
`topic_popover.ts` and `stream_popover.ts` on
|
||||
`.inbox-action-button`) and `visibility-policy-popover-visible`
|
||||
(added by `user_topic_popover.ts` on the visibility-policy
|
||||
wrappers) — without enumerating element/class combinations,
|
||||
and stays correct if a future popover follows the same
|
||||
naming convention. */
|
||||
[class*="-popover-visible"] {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.inbox-action-button {
|
||||
outline: none;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
& i {
|
||||
/* Match the color used by `.recipient_bar_icon` on
|
||||
the state marker icons, so the 3-dots and the
|
||||
follow/mute/unmute markers render in the same hue
|
||||
as row-attention elevates both to visible. */
|
||||
color: var(--color-message-header-icon-interactive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-header-stream-archived {
|
||||
color: var(--color-text-message-header-archived);
|
||||
margin-left: 0.3125em; /* 5px at 16px em */
|
||||
}
|
||||
}
|
||||
|
||||
#inbox-view {
|
||||
display: none;
|
||||
position: relative;
|
||||
|
||||
.inbox-folder {
|
||||
margin-bottom: 1px;
|
||||
background-color: transparent;
|
||||
|
||||
.inbox-header-name-text,
|
||||
.unread_mention_info {
|
||||
color: var(--color-folder-header);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.inbox-header-name-text {
|
||||
font-style: normal;
|
||||
font-weight: var(--font-weight-sidebar-heading);
|
||||
line-height: 112.5%;
|
||||
letter-spacing: var(--letter-spacing-sidebar-heading);
|
||||
text-transform: uppercase;
|
||||
outline: none;
|
||||
/* 16px at 16px / 1em */
|
||||
font-size: 1em;
|
||||
/* Align the folder title with the channel privacy icons; 5px at 16px/1em.
|
||||
|
||||
TODO: Reduce the depth of selectors in this file,
|
||||
so that the use of !important becomes unnecessary
|
||||
here. */
|
||||
padding-left: 0.3125em !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.inbox-header-name-text,
|
||||
.collapsible-button .zulip-icon,
|
||||
.unread_mention_info,
|
||||
.unread_count {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hidden_by_filters {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.channel-folders-inbox-menu-icon {
|
||||
display: grid;
|
||||
/* width excluding left & right margin */
|
||||
width: calc(var(--left-sidebar-vdots-width) - 4px);
|
||||
cursor: pointer;
|
||||
place-items: center center;
|
||||
border-radius: 3px;
|
||||
margin: 2px;
|
||||
color: var(--color-vdots-visible);
|
||||
|
||||
i.zulip-icon {
|
||||
font-size: 1.0625em;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--color-vdots-hover);
|
||||
background-color: var(--color-background-sidebar-action-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-container #inbox-pane #inbox-empty-without-search {
|
||||
margin-top: 70px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.inbox-empty-illustration {
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
margin-bottom: 16px;
|
||||
background-color: var(--color-background-inbox-no-unreads-illustration);
|
||||
mask: url("../images/empty-view-illustrations/inbox-done.svg") no-repeat
|
||||
center;
|
||||
}
|
||||
|
||||
.inbox-empty-title {
|
||||
/* Matches the font-size used for .empty-list-message */
|
||||
font-size: 1.5em;
|
||||
color: var(--color-background-inbox-no-unreads-illustration);
|
||||
}
|
||||
|
||||
.inbox-empty-action {
|
||||
font-size: 1.3em;
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
.inbox-container #inbox-pane .inbox-empty-action-link {
|
||||
color: var(--color-text-url);
|
||||
|
||||
&:hover {
|
||||
color: var(--color-text-url-hover);
|
||||
}
|
||||
}
|
||||
|
||||
#inbox-filter_widget {
|
||||
margin-right: 0.3571em; /* 5px / 14px em */
|
||||
max-width: var(--width-inbox-filters-dropdown);
|
||||
border: 1px solid var(--color-border-inbox-search);
|
||||
background-color: var(--color-background-inbox-search);
|
||||
gap: 0.3571em; /* 5px / 14px em */
|
||||
/* 1.5px at 16px/1em and legacy 6px at 14px/1em. */
|
||||
padding: 0.0937em 0.4285em;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-background-inbox-search-hover);
|
||||
border: 1px solid var(--color-border-inbox-search-hover);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
#recent-view-filter_widget .dropdown_widget_value,
|
||||
#inbox-filter_widget .dropdown_widget_value {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#recent-view-filter_widget .zulip-icon-chevron-down,
|
||||
#inbox-filter_widget .zulip-icon-chevron-down {
|
||||
color: var(--color-icons-inbox);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.recent-view-filter-dropdown-list-container .dropdown-list-wrapper,
|
||||
.inbox-filter-dropdown-list-container .dropdown-list-wrapper,
|
||||
.new_channel_privacy-dropdown-list-container .dropdown-list-wrapper,
|
||||
.channel_privacy-dropdown-list-container .dropdown-list-wrapper {
|
||||
/* We want these dropdowns to open to fit their
|
||||
contents, which differ based on the language
|
||||
in use. */
|
||||
width: 100%;
|
||||
/* We also don't want to set a min-width, again
|
||||
so that the content is in charge. This pushes
|
||||
back against more generic styles. */
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
.recent-view-filter-dropdown-list-container
|
||||
.dropdown-list
|
||||
.dropdown-list-item-common-styles,
|
||||
.inbox-filter-dropdown-list-container
|
||||
.dropdown-list
|
||||
.dropdown-list-item-common-styles,
|
||||
.new_channel_privacy-dropdown-list-container
|
||||
.dropdown-list
|
||||
.dropdown-list-item-common-styles,
|
||||
.channel_privacy-dropdown-list-container
|
||||
.dropdown-list
|
||||
.dropdown-list-item-common-styles {
|
||||
/* Parallel to the `width: 100%` set on
|
||||
.dropdown-list-wrapper above, we set
|
||||
min-width here to max-content so that
|
||||
the box opens to accommodate different
|
||||
lengths of text--and to ensure that
|
||||
hovered/selectable areas look correct. */
|
||||
min-width: max-content;
|
||||
padding: 5px 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* For columnar flex items, we need
|
||||
to make set alignment to the start
|
||||
of the flex container. This pushes
|
||||
back against non-columnar flexboxes
|
||||
that require centered alignment. */
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.recent-view-filter-dropdown-list-container .dropdown-list-item-name,
|
||||
.inbox-filter-dropdown-list-container .dropdown-list-item-name,
|
||||
.new_channel_privacy-dropdown-list-container .dropdown-list-item-name,
|
||||
.channel_privacy-dropdown-list-container .dropdown-list-item-name {
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.recent-view-filter-dropdown-list-container .dropdown-list-item-description,
|
||||
.inbox-filter-dropdown-list-container .dropdown-list-item-description,
|
||||
.channel_privacy-dropdown-list-container .dropdown-list-item-description,
|
||||
.new_channel_privacy-dropdown-list-container .dropdown-list-item-description {
|
||||
white-space: nowrap;
|
||||
font-weight: 400;
|
||||
font-size: 0.9285em; /* 13px at 14px em */
|
||||
opacity: 0.8;
|
||||
padding: 0;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.inbox-container #inbox-pane .inbox-folder .unread_count {
|
||||
transition: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#inbox-pane #inbox-list .collapsible-button {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#inbox-pane #inbox-list .inbox-collapsed-state .collapsible-button {
|
||||
visibility: visible;
|
||||
|
||||
.zulip-icon-chevron-down {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
.folder-row-chevron {
|
||||
color: var(--color-folder-header);
|
||||
}
|
||||
|
||||
.channel-row-chevron {
|
||||
color: var(--color-inbox-row-chevron);
|
||||
}
|
||||
|
||||
.inbox-collapsed-state {
|
||||
.folder-row-chevron,
|
||||
.channel-row-chevron {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-container #inbox-pane .inbox-folder .unread_mention_info {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.inbox-container
|
||||
#inbox-pane
|
||||
.inbox-folder.inbox-collapsed-state
|
||||
.unread_mention_info,
|
||||
.inbox-container #inbox-pane .inbox-folder.inbox-collapsed-state .unread_count {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.inbox-folder-components {
|
||||
border-radius: 5px;
|
||||
border: var(--inbox-view-folder-component-border-width) solid
|
||||
var(--color-border-inbox-folder-component);
|
||||
overflow: hidden;
|
||||
|
||||
&:has(.inbox-row:not(.hidden_by_filters)),
|
||||
&:has(.inbox-header:not(.hidden_by_filters)) {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-folder.inbox-collapsed-state,
|
||||
.inbox-folder.hidden_by_filters {
|
||||
+ .inbox-folder-components {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#inbox-pane #inbox-list .inbox-collapsed-state {
|
||||
+ .inbox-folder-components,
|
||||
+ .inbox-topic-container {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#inbox-pane
|
||||
#inbox-list
|
||||
.inbox-streams-container
|
||||
.inbox-header
|
||||
.inbox-header-name {
|
||||
/* 5px at 16px / 1em */
|
||||
padding: 1px 0.3125em 1px 0;
|
||||
}
|
||||
|
||||
#inbox-view.no-visible-focus-outlines
|
||||
.inbox-container
|
||||
#inbox-pane
|
||||
[tabindex="0"] {
|
||||
/* Remove default focus outline from elements. */
|
||||
&:focus-visible {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#inbox-view:not(.no-visible-focus-outlines) .inbox-container #inbox-pane {
|
||||
/* Only show focus outlines when user uses keyboard. */
|
||||
#inbox-filter_widget {
|
||||
&:focus-visible {
|
||||
outline: var(--focus-ring-outline);
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-row,
|
||||
.inbox-header {
|
||||
&:focus-visible {
|
||||
/* Flush outline on the row itself instead of the old
|
||||
2px inner-border on `.inbox-focus-border`; matches
|
||||
`.recent-view-body-row`'s focus style, but inbox rows
|
||||
are tighter (30px) so the outline sits at the row
|
||||
edges instead of insetting 4px. */
|
||||
outline: var(--focus-ring-outline);
|
||||
outline-offset: var(--focus-ring-outline-offset-in-views);
|
||||
border-radius: 0.3125em; /* 5px at 16px/1em */
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-header:focus-visible {
|
||||
.collapsible-button > .zulip-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.collapsible-button {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
/* Focus ring for the icon-style row actions. Outline lives on
|
||||
the wrapper (at full opacity) so the ring renders at full
|
||||
blue saturation and meets WCAG 1.4.11's 3:1 contrast
|
||||
requirement for focus indicators. Negative outline-offset
|
||||
pulls the 1.5px stroke inside the 30×30 wrapper bounds so it
|
||||
doesn't clip against the row's overflow:hidden edge, giving
|
||||
a 26×26 effective ring. The inner icon dims separately. */
|
||||
.channel-visibility-policy-indicator,
|
||||
.visibility-policy-indicator,
|
||||
.inbox-action-button {
|
||||
&:focus-visible {
|
||||
outline: var(--focus-ring-outline);
|
||||
outline-offset: -0.125em; /* -2px at 16px/1em */
|
||||
border-radius: 0.3125em; /* 5px at 16px/1em */
|
||||
|
||||
> i,
|
||||
> .zulip-icon,
|
||||
> .recipient_bar_icon {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Focus ring drawn as a pseudo-element on the inner badge,
|
||||
with `5px` of breathing room outside the badge. A
|
||||
wrapper-sized outline (the previous implementation) leaves a
|
||||
wide gap between the ring and the badge fill that reads as a
|
||||
second concentric outline; the deliberate 5px gap here reads
|
||||
as padding around a single badge instead. */
|
||||
.unread-count-focus-outline {
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
|
||||
.unread_count {
|
||||
position: relative;
|
||||
|
||||
/* Suppress the inner `.normal-count` `inset`
|
||||
`box-shadow` so it doesn't sit as a second,
|
||||
narrower outline inside the focus ring. */
|
||||
box-shadow: none;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -0.3125em; /* -5px at 16px/1em */
|
||||
border: var(--focus-ring-outline);
|
||||
border-radius: var(
|
||||
--unread-count-focus-outline-radius-in-views
|
||||
);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-folder {
|
||||
&:focus-visible {
|
||||
.inbox-header-name-text,
|
||||
.collapsible-button .zulip-icon,
|
||||
.unread_mention_info,
|
||||
.unread_count {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
background: light-dark(
|
||||
transparent,
|
||||
var(--color-background-hover-popover-menu)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#inbox-view .inbox-container #inbox-pane #inbox-expand-all-button {
|
||||
--color-outline-button-focus: var(--color-outline-focus);
|
||||
--outline-offset-button-focus: var(--focus-ring-outline-offset-in-views);
|
||||
}
|
||||
|
||||
#inbox-animation-extra-content-blocker {
|
||||
background: var(--color-background-inbox);
|
||||
}
|
||||
Reference in New Issue
Block a user