compose: Redesign limit indicator to show remaining characters count.

Additionally, the text colors have been updated for both light and dark
themes, it starts showing when 900 or less characters are left, as 999
was too soon, and has a tooltip to show the maximum characters limit.

Fixes: #28706.
This commit is contained in:
N-Shar-ma 2024-04-24 12:16:47 +05:30 committed by Tim Abbott
parent de90d0acdf
commit bfbf4f6f68
7 changed files with 25 additions and 17 deletions

View File

@ -66,7 +66,10 @@ function update_send_button_status(): void {
export function get_disabled_send_tooltip(): string { export function get_disabled_send_tooltip(): string {
if (message_too_long) { if (message_too_long) {
return $t({defaultMessage: "Message length shouldn't be greater than 10000 characters."}); return $t(
{defaultMessage: `Message length shouldn't be greater than {max_length} characters.`},
{max_length: realm.max_message_length},
);
} else if (upload_in_progress) { } else if (upload_in_progress) {
return $t({defaultMessage: "Cannot send message while files are being uploaded."}); return $t({defaultMessage: "Cannot send message while files are being uploaded."});
} }
@ -689,6 +692,7 @@ export function check_overflow_text(): number {
// expensive. // expensive.
const text = compose_state.message_content(); const text = compose_state.message_content();
const max_length = realm.max_message_length; const max_length = realm.max_message_length;
const remaining_characters = max_length - text.length;
const $indicator = $("#compose-limit-indicator"); const $indicator = $("#compose-limit-indicator");
if (text.length > max_length) { if (text.length > max_length) {
@ -696,8 +700,7 @@ export function check_overflow_text(): number {
$("textarea#compose-textarea").addClass("over_limit"); $("textarea#compose-textarea").addClass("over_limit");
$indicator.html( $indicator.html(
render_compose_limit_indicator({ render_compose_limit_indicator({
text_length: text.length, remaining_characters,
max_length,
}), }),
); );
compose_banner.show_error_message( compose_banner.show_error_message(
@ -712,13 +715,12 @@ export function check_overflow_text(): number {
$("#compose_banners"), $("#compose_banners"),
); );
set_message_too_long(true); set_message_too_long(true);
} else if (text.length > 0.9 * max_length) { } else if (remaining_characters <= 900) {
$indicator.removeClass("over_limit"); $indicator.removeClass("over_limit");
$("textarea#compose-textarea").removeClass("over_limit"); $("textarea#compose-textarea").removeClass("over_limit");
$indicator.html( $indicator.html(
render_compose_limit_indicator({ render_compose_limit_indicator({
text_length: text.length, remaining_characters,
max_length,
}), }),
); );
set_message_too_long(false); set_message_too_long(false);

View File

@ -181,6 +181,7 @@ function initialize_compose_box() {
giphy_enabled: giphy.is_giphy_enabled(), giphy_enabled: giphy.is_giphy_enabled(),
max_stream_name_length: realm.max_stream_name_length, max_stream_name_length: realm.max_stream_name_length,
max_topic_length: realm.max_topic_length, max_topic_length: realm.max_topic_length,
max_message_length: realm.max_message_length,
}), }),
), ),
); );

View File

@ -276,6 +276,8 @@
231deg 100% 90% / 50% 231deg 100% 90% / 50%
); );
--color-compose-chevron-arrow: hsl(0deg 0% 58%); --color-compose-chevron-arrow: hsl(0deg 0% 58%);
--color-limit-indicator: hsl(38deg 100% 36%);
--color-limit-indicator-over-limit: hsl(3deg 80% 40%);
/* Text colors */ /* Text colors */
--color-text-default: hsl(0deg 0% 20%); --color-text-default: hsl(0deg 0% 20%);
@ -585,6 +587,8 @@
235deg 100% 70% / 11% 235deg 100% 70% / 11%
); );
--color-background-popover: hsl(212deg 32% 14%); --color-background-popover: hsl(212deg 32% 14%);
--color-limit-indicator: hsl(38deg 100% 70%);
--color-limit-indicator-over-limit: hsl(3deg 80% 60%);
/* Text colors */ /* Text colors */
--color-text-default: hsl(0deg 0% 100% / 75%); --color-text-default: hsl(0deg 0% 100% / 75%);

View File

@ -304,14 +304,16 @@
#compose-limit-indicator { #compose-limit-indicator {
font-size: 12px; font-size: 12px;
color: hsl(39deg 100% 50%); color: var(--color-limit-indicator);
width: max-content;
/* Keep the limit indicator /* Keep the limit indicator just above
just above the send button */ and aligned with the send button */
margin-top: auto; margin-top: auto;
padding: 3px 3px 3px 0;
&.over_limit { &.over_limit {
color: hsl(0deg 76% 65%); color: var(--color-limit-indicator-over-limit);
font-weight: bold; font-weight: bold;
} }
} }

View File

@ -89,7 +89,7 @@
<a id="compose-drafts-button" role="button" class="send-control-button hide-sm" tabindex=0 href="#drafts"> <a id="compose-drafts-button" role="button" class="send-control-button hide-sm" tabindex=0 href="#drafts">
<span class="compose-drafts-text">{{t 'Drafts' }}</span><span class="compose-drafts-count-container">(<span class="compose-drafts-count"></span>)</span> <span class="compose-drafts-text">{{t 'Drafts' }}</span><span class="compose-drafts-count-container">(<span class="compose-drafts-count"></span>)</span>
</a> </a>
<span id="compose-limit-indicator"></span> <span id="compose-limit-indicator" class="tippy-zulip-tooltip" data-tippy-content="{{t 'Maximum message length: {max_message_length} characters' }}"></span>
<div class="message-send-controls"> <div class="message-send-controls">
<button type="submit" id="compose-send-button" class="send_message compose-submit-button compose-send-or-save-button" aria-label="{{t 'Send' }}"> <button type="submit" id="compose-send-button" class="send_message compose-submit-button compose-send-or-save-button" aria-label="{{t 'Send' }}">
<img class="loader" alt="" src="" /> <img class="loader" alt="" src="" />

View File

@ -1,2 +1 @@
{{! Include a zero-width-space to allow breaks in narrow compose boxes. }} {{remaining_characters}}
{{text_length}}&ZeroWidthSpace;/{{max_length}}

View File

@ -546,24 +546,24 @@ test_ui("test_check_overflow_text", ({mock_template}) => {
$textarea.val("a".repeat(10000 + 1)); $textarea.val("a".repeat(10000 + 1));
compose_validate.check_overflow_text(); compose_validate.check_overflow_text();
assert.ok($indicator.hasClass("over_limit")); assert.ok($indicator.hasClass("over_limit"));
assert.equal(limit_indicator_html, "10001&ZeroWidthSpace;/10000\n"); assert.equal(limit_indicator_html, "-1\n");
assert.ok($textarea.hasClass("over_limit")); assert.ok($textarea.hasClass("over_limit"));
assert.ok(banner_rendered); assert.ok(banner_rendered);
assert.ok($(".message-send-controls").hasClass("disabled-message-send-controls")); assert.ok($(".message-send-controls").hasClass("disabled-message-send-controls"));
// Indicator should show orange colored text // Indicator should show orange colored text
banner_rendered = false; banner_rendered = false;
$textarea.val("a".repeat(9000 + 1)); $textarea.val("a".repeat(9100));
compose_validate.check_overflow_text(); compose_validate.check_overflow_text();
assert.ok(!$indicator.hasClass("over_limit")); assert.ok(!$indicator.hasClass("over_limit"));
assert.equal(limit_indicator_html, "9001&ZeroWidthSpace;/10000\n"); assert.equal(limit_indicator_html, "900\n");
assert.ok(!$textarea.hasClass("over_limit")); assert.ok(!$textarea.hasClass("over_limit"));
assert.ok(!$(".message-send-controls").hasClass("disabled-message-send-controls")); assert.ok(!$(".message-send-controls").hasClass("disabled-message-send-controls"));
assert.ok(!banner_rendered); assert.ok(!banner_rendered);
// Indicator must be empty // Indicator must be empty
banner_rendered = false; banner_rendered = false;
$textarea.val("a".repeat(9000)); $textarea.val("a".repeat(9100 - 1));
compose_validate.check_overflow_text(); compose_validate.check_overflow_text();
assert.ok(!$indicator.hasClass("over_limit")); assert.ok(!$indicator.hasClass("over_limit"));
assert.equal($indicator.text(), ""); assert.equal($indicator.text(), "");