diff --git a/web/src/color_class.ts b/web/src/color_class.ts deleted file mode 100644 index 678dfe0b71ce0..0000000000000 --- a/web/src/color_class.ts +++ /dev/null @@ -1,57 +0,0 @@ -import _ from "lodash"; - -import * as colorspace from "./colorspace"; - -export function get_threshold(): number { - // sRGB color component for dark label text. - // 0x33 to match the color #333333 set by Bootstrap. - const label_color = 0x33; - const lightness = colorspace.luminance_to_lightness(colorspace.sRGB_to_linear(label_color)); - - // Compute midpoint lightness between that and white (100). - return (lightness + 100) / 2; -} - -const lightness_threshold = get_threshold(); - -// From a background color (in format "#fff" or "#ffffff") -// pick a CSS class (or empty string) to determine the -// text label color etc. -// -// It would be better to work with an actual data structure -// rather than a hex string, but we have to deal with values -// already saved on the server, etc. -// -// This gets called on every message, so cache the results. -export const get_css_class = _.memoize((color: string) => { - let match; - let i; - const channel: [number, number, number] = [0, 0, 0]; - let mult = 1; - - match = /^#([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})$/.exec(color); - if (!match) { - // 3-digit shorthand; Spectrum gives this e.g. for pure black. - // Multiply each digit by 16+1. - mult = 17; - - match = /^#([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])$/.exec(color); - if (!match) { - // Can't understand color. - return ""; - } - } - - // CSS colors are specified in the sRGB color space. - // Convert to linear intensity values. - for (i = 0; i < 3; i += 1) { - channel[i] = colorspace.sRGB_to_linear(mult * Number.parseInt(match[i + 1], 16)); - } - - // Compute perceived lightness as CIE L*. - const lightness = colorspace.luminance_to_lightness(colorspace.rgb_luminance(channel)); - - // Determine if we're past the midpoint between the - // dark and light label lightness. - return lightness < lightness_threshold ? "dark_background" : ""; -}); diff --git a/web/src/drafts.js b/web/src/drafts.js index baf4a2bbdb119..e2ac3549cb6f5 100644 --- a/web/src/drafts.js +++ b/web/src/drafts.js @@ -370,6 +370,7 @@ export function format_draft(draft) { draft_id: draft.id, is_stream: true, stream_name, + recipient_bar_color: stream_color.get_recipient_bar_color(draft_stream_color), stream_privacy_icon_color: stream_color.get_stream_privacy_icon_color(draft_stream_color), topic: draft_topic, diff --git a/web/src/message_list_view.js b/web/src/message_list_view.js index 879c9bfb7d23a..a5b592c7520a0 100644 --- a/web/src/message_list_view.js +++ b/web/src/message_list_view.js @@ -11,7 +11,6 @@ import render_single_message from "../templates/single_message.hbs"; import * as activity from "./activity"; import * as blueslip from "./blueslip"; -import * as color_class from "./color_class"; import * as compose from "./compose"; import * as compose_fade from "./compose_fade"; import * as condense from "./condense"; @@ -174,9 +173,8 @@ function populate_group_from_message_container(group, message_container) { group.is_private = message_container.msg.is_private; if (group.is_stream) { - group.background_color = stream_data.get_color(message_container.msg.stream); - group.color_class = color_class.get_css_class(group.background_color); const color = stream_data.get_color(message_container.msg.stream); + group.recipient_bar_color = stream_color.get_recipient_bar_color(color); group.stream_privacy_icon_color = stream_color.get_stream_privacy_icon_color(color); group.invite_only = stream_data.is_invite_only_by_stream_name(message_container.msg.stream); group.is_web_public = stream_data.is_web_public(message_container.msg.stream_id); @@ -1558,4 +1556,13 @@ export class MessageListView { } } } + + update_recipient_bar_background_color() { + const $table = rows.get_table(this.table_name); + const $stream_headers = $table.find(".message_header_stream"); + for (const stream_header of $stream_headers) { + const $stream_header = $(stream_header); + stream_color.update_stream_recipient_color($stream_header); + } + } } diff --git a/web/src/message_lists.js b/web/src/message_lists.js index 7ade9aad716bc..758bb1d3eeb02 100644 --- a/web/src/message_lists.js +++ b/web/src/message_lists.js @@ -17,6 +17,12 @@ export function all_rendered_message_lists() { return rendered_message_lists; } +export function update_recipient_bar_background_color() { + for (const msg_list of all_rendered_message_lists()) { + msg_list.view.update_recipient_bar_background_color(); + } +} + export function initialize() { home = new message_list.MessageList({ table_name: "zhome", diff --git a/web/src/server_events_dispatch.js b/web/src/server_events_dispatch.js index 79cc68fa83930..42e230e8a9dcd 100644 --- a/web/src/server_events_dispatch.js +++ b/web/src/server_events_dispatch.js @@ -689,6 +689,7 @@ export function dispatch_normal_event(event) { realm_logo.render(); } $("body").fadeIn(300); + message_lists.update_recipient_bar_background_color(); }, 300); } if (event.property === "starred_message_counts") { diff --git a/web/src/stream_bar.js b/web/src/stream_bar.js index e84274dd17aac..85f6c68b1667d 100644 --- a/web/src/stream_bar.js +++ b/web/src/stream_bar.js @@ -1,6 +1,5 @@ import $ from "jquery"; -import * as color_class from "./color_class"; import * as stream_data from "./stream_data"; function update_compose_stream_icon(stream_name) { @@ -34,8 +33,5 @@ export function decorate(stream_name, $element, is_compose) { if (is_compose) { update_compose_stream_icon(stream_name); } - $element - .css("background-color", color) - .removeClass("dark_background") - .addClass(color_class.get_css_class(color)); + $element.css("background-color", color); } diff --git a/web/src/stream_color.js b/web/src/stream_color.js index 109e50827734d..177921eb58457 100644 --- a/web/src/stream_color.js +++ b/web/src/stream_color.js @@ -1,12 +1,33 @@ import {colord, extend} from "colord"; +import lchPlugin from "colord/plugins/lch"; +import mixPlugin from "colord/plugins/mix"; import $ from "jquery"; -import * as color_class from "./color_class"; import {$t} from "./i18n"; +import * as message_lists from "./message_lists"; import * as message_view_header from "./message_view_header"; +import * as overlays from "./overlays"; +import * as row from "./rows"; +import * as settings_data from "./settings_data"; +import * as stream_data from "./stream_data"; import * as stream_settings_ui from "./stream_settings_ui"; -extend([lchPlugin]); +extend([lchPlugin, mixPlugin]); + +export function update_stream_recipient_color($stream_header) { + if ($stream_header.length) { + const stream_id = Number.parseInt($($stream_header).attr("data-stream-id"), 10); + const stream_name = stream_data.maybe_get_stream_name(stream_id); + if (!stream_name) { + return; + } + const stream_color = stream_data.get_color(stream_name); + const recipient_bar_color = get_recipient_bar_color(stream_color); + $stream_header + .find(".message-header-contents") + .css("background-color", recipient_bar_color); + } +} export function get_stream_privacy_icon_color(color) { // LCH stands for Lightness, Chroma, and Hue. @@ -22,28 +43,23 @@ export function get_stream_privacy_icon_color(color) { return colord(color).toHex(); } +export function get_recipient_bar_color(color) { + // Mixes 50% of color to 40% of white (light theme) / black (dark theme). + const using_dark_theme = settings_data.using_dark_theme(); + color = get_stream_privacy_icon_color(color); + return colord(using_dark_theme ? "#000000" : "#ffffff") + .mix(color, using_dark_theme ? 0.5 : 0.4) + .toHex(); +} +function update_table_message_recipient_stream_color(table, stream_name, recipient_bar_color) { const $stream_labels = table.find(".stream_label"); - for (const label of $stream_labels) { const $label = $(label); if ($label.text().trim() === stream_name) { - const $messages = $label.closest(".recipient_row").children(".message_row"); - $messages - .children(".messagebox") - .css( - "box-shadow", - "inset 2px 0px 0px 0px " + style + ", -1px 0px 0px 0px " + style, - ); - $messages - .children(".date_row") - .css( - "box-shadow", - "inset 2px 0px 0px 0px " + style + ", -1px 0px 0px 0px " + style, - ); - $label.css({background: style, "border-left-color": style}); - $label.removeClass("dark_background"); - $label.addClass(color_class.get_css_class(color)); + $label + .closest(".message_header_stream .message-header-contents") + .css({background: recipient_bar_color}); } } } @@ -55,10 +71,20 @@ function update_stream_privacy_color(id, color) { $(`.stream-privacy-modified-color-${CSS.escape(id)}`).css("color", color); } -function update_historical_message_color(stream_name, color) { - update_table_stream_color($(".focused_table"), stream_name, color); - if ($(".focused_table").attr("id") !== "#zhome") { - update_table_stream_color($("#zhome"), stream_name, color); +function update_message_recipient_color(stream_name, color) { + const recipient_color = get_recipient_bar_color(color); + for (const msg_list of message_lists.all_rendered_message_lists()) { + const $table = row.get_table(msg_list.table_name); + update_table_message_recipient_stream_color($table, stream_name, recipient_color); + } + + // Update color for drafts if open. + if (overlays.drafts_open()) { + update_table_message_recipient_stream_color( + $(".drafts-container"), + stream_name, + recipient_color, + ); } } @@ -107,7 +133,7 @@ export function update_stream_color(sub, color) { )}'] .large-icon`, ).css("color", color); - update_historical_message_color(sub.name, color); + update_message_recipient_color(sub.name, color); update_stream_privacy_color(stream_id, color); message_view_header.colorize_message_view_header(); } diff --git a/web/src/stream_list.js b/web/src/stream_list.js index 1719fbf2bbd0f..286a53728f941 100644 --- a/web/src/stream_list.js +++ b/web/src/stream_list.js @@ -8,7 +8,6 @@ import render_stream_subheader from "../templates/streams_subheader.hbs"; import render_subscribe_to_more_streams from "../templates/subscribe_to_more_streams.hbs"; import * as blueslip from "./blueslip"; -import * as color_class from "./color_class"; import * as hash_util from "./hash_util"; import {$t} from "./i18n"; import * as keydown_util from "./keydown_util"; @@ -325,7 +324,6 @@ function build_stream_sidebar_li(sub) { color: sub.color, pin_to_top: sub.pin_to_top, }; - args.dark_background = color_class.get_css_class(args.color); const $list_item = $(render_stream_sidebar_row(args)); return $list_item; } @@ -385,12 +383,10 @@ export function redraw_stream_privacy(sub) { } const $div = $li.find(".stream-privacy"); - const dark_background = color_class.get_css_class(sub.color); const args = { invite_only: sub.invite_only, is_web_public: sub.is_web_public, - dark_background, }; const html = render_stream_privacy(args); diff --git a/web/styles/dark_theme.css b/web/styles/dark_theme.css index ab9d4648b84d8..8273350c4d6fe 100644 --- a/web/styles/dark_theme.css +++ b/web/styles/dark_theme.css @@ -315,12 +315,6 @@ border-color: hsl(0deg 0% 0% / 20%); } - .dark .message_label_clickable.stream_label, - .dark .stream_label, - .stream_label { - color: hsl(212deg 28% 18%); - } - .new-style label.checkbox input[type="checkbox"] ~ span { border-color: hsl(0deg 0% 100% / 40%); } @@ -344,9 +338,6 @@ color: inherit; } - .dark_background a, - a.dark_background:hover, - .dark_background, .message_reactions .message_reaction_count, .message_reactions .reaction_button i, .message_reactions:hover .message_reaction + .reaction_button { @@ -372,13 +363,6 @@ } } - /* do not turn the .message_header .stream_label text dark on hover because they're - on a dark background, and don't change the dark labels dark either. */ - .message_header:not(.dark_background) - a.stream_label:not(.dark_background):hover { - color: hsl(212deg 28% 18%); - } - .message_header { box-shadow: 0 -1px 0 0 hsl(212deg 28% 18%); } diff --git a/web/styles/zulip.css b/web/styles/zulip.css index 18cd309cc7837..0b4bbb406b796 100644 --- a/web/styles/zulip.css +++ b/web/styles/zulip.css @@ -1456,18 +1456,6 @@ td.pointer { visibility: visible; } -/* Brighten text because of the dark background */ -.dark_background a, -.dark_background a:hover, -a.dark_background:hover, -.dark_background { - color: hsl(0deg 0% 100%) !important; -} - -.dark_background a.message_label_clickable:hover { - color: hsl(200deg 99% 60%); -} - .small { font-size: 80%; } diff --git a/web/templates/draft.hbs b/web/templates/draft.hbs index 42c5c8f402250..8b8f86df26a9e 100644 --- a/web/templates/draft.hbs +++ b/web/templates/draft.hbs @@ -2,14 +2,13 @@
{{#if is_stream}}
-
+
{{> stream_privacy}} {{stream_name}}
-
{{topic}} @@ -20,7 +19,7 @@
{{else}} -
+
{{t "You and {recipients}" }} diff --git a/web/templates/recipient_row.hbs b/web/templates/recipient_row.hbs index 6a48578696ebb..a70f6bcc88301 100644 --- a/web/templates/recipient_row.hbs +++ b/web/templates/recipient_row.hbs @@ -1,9 +1,8 @@ {{#if is_stream}} -
-
+
+
{{! stream link }} - @@ -75,7 +74,7 @@
{{else}} -
+
{ draft_id: "id1", is_stream: true, stream_name: "stream", - stream_color: "#FFFFFF", - dark_background: "", + stream_id: 30, + recipient_bar_color: "#e2e2e2", + stream_privacy_icon_color: "#b9b9b9", topic: "topic", raw_content: "Test stream message", time_stamp: "7:55 AM", + invite_only: undefined, + is_web_public: undefined, }, { draft_id: "id2", @@ -547,11 +550,14 @@ test("format_drafts", ({override_rewire, mock_template}) => { draft_id: "id3", is_stream: true, stream_name: "stream 2", - stream_color: "#FFFFFF", - dark_background: "", + recipient_bar_color: "#e2e2e2", + stream_privacy_icon_color: "#b9b9b9", topic: "topic", raw_content: "Test stream message 2", time_stamp: "Jan 21", + stream_id: undefined, + invite_only: false, + is_web_public: false, }, ]; @@ -681,21 +687,27 @@ test("filter_drafts", ({override_rewire, mock_template}) => { draft_id: "id1", is_stream: true, stream_name: "stream", - stream_color: "#FFFFFF", - dark_background: "", + stream_id: 30, + recipient_bar_color: "#e2e2e2", + stream_privacy_icon_color: "#b9b9b9", topic: "topic", raw_content: "Test stream message", time_stamp: "7:55 AM", + invite_only: false, + is_web_public: false, }, { draft_id: "id3", is_stream: true, stream_name: "stream 2", - stream_color: "#FFFFFF", - dark_background: "", + stream_id: undefined, + recipient_bar_color: "#e2e2e2", + stream_privacy_icon_color: "#b9b9b9", topic: "topic", raw_content: "Test stream message 2", time_stamp: "Jan 21", + invite_only: false, + is_web_public: false, }, ]; @@ -720,7 +732,7 @@ test("filter_drafts", ({override_rewire, mock_template}) => { sub_store.get = function (stream_id) { assert.equal(stream_id, 30); - return {name: "stream"}; + return {name: "stream", invite_only: false, is_web_public: false}; }; mock_template("draft_table_body.hbs", false, (data) => { diff --git a/web/tests/stream_list.test.js b/web/tests/stream_list.test.js index 9df43a7e4e342..4081206a70b29 100644 --- a/web/tests/stream_list.test.js +++ b/web/tests/stream_list.test.js @@ -182,7 +182,6 @@ test_ui("create_sidebar_row", ({override_rewire, mock_template}) => { mock_template("stream_privacy.hbs", false, (data) => { assert.equal(data.invite_only, true); - assert.equal(data.dark_background, "dark_background"); return "
privacy-html"; }); stream_list.redraw_stream_privacy(social); @@ -668,7 +667,6 @@ test_ui("rename_stream", ({mock_template}) => { is_web_public: undefined, color: payload.color, pin_to_top: true, - dark_background: payload.dark_background, }); return {to_$: () => $li_stub}; });