user_status: Add UI changes for status emoji feature.

In this commit, we update the UI to:

*  Display emoji on the buddy list (right side sidebar).

*  Display the emoji picker on the set status overlay.

It also updates the `z-index` of
`#set_user_status_modal`, which was changed from 105
to 1050 in 166bfa4cf8. We change it back to 105, so
emoji-popover can be visible on top of the
`#set_user_status_modal`.

We also remove the `tabindex` property from the
`#set_user_status_modal` so it can allow keyboard
events for emoji popover.
This commit is contained in:
Riken Shah 2021-06-28 08:02:45 +00:00 committed by Tim Abbott
parent 840ab92f7f
commit 297379029d
8 changed files with 169 additions and 20 deletions

View File

@ -12,6 +12,7 @@ import * as blueslip from "./blueslip";
import * as compose_ui from "./compose_ui";
import * as message_lists from "./message_lists";
import * as message_store from "./message_store";
import {page_params} from "./page_params";
import * as popovers from "./popovers";
import * as reactions from "./reactions";
import * as rows from "./rows";
@ -190,6 +191,12 @@ export function reactions_popped() {
export function hide_emoji_popover() {
$(".has_popover").removeClass("has_popover has_emoji_popover");
if (user_status_ui.user_status_picker_open()) {
// Re-enable clicking events for other elements after closing
// the popover. This is the inverse of the hack of in the
// handler that opens the "user status modal" emoji picker.
$(".app, .header, .modal-backdrop, #set_user_status_modal").css("pointer-events", "all");
}
if (reactions_popped()) {
current_message_emoji_popover_elem.popover("destroy");
current_message_emoji_popover_elem.removeClass("reaction_button_visible");
@ -761,6 +768,31 @@ export function register_click_handlers() {
true,
);
});
$("body").on("click", "#set_user_status_modal #selected_emoji", (e) => {
e.preventDefault();
e.stopPropagation();
toggle_emoji_popover(e.target);
// Because the emoji picker gets drawn on top of the user
// status modal, we need this hack to make clicking outside
// the emoji picker only close the emoji picker, and not the
// whole user status modal.
$(".app, .header, .modal-backdrop, #set_user_status_modal").css("pointer-events", "none");
});
$(document).on("click", ".emoji-popover-emoji.status_emoji", function (e) {
e.preventDefault();
e.stopPropagation();
hide_emoji_popover();
const emoji_name = $(this).attr("data-emoji-name");
let emoji_info = {emoji_name, emoji_alt_code: page_params.emojiset === "text"};
if (!emoji_info.emoji_alt_code) {
emoji_info = {...emoji_info, ...emoji.get_emoji_details_by_name(emoji_name)};
}
user_status_ui.set_selected_emoji_info(emoji_info);
user_status_ui.update_button();
user_status_ui.toggle_clear_message_button();
});
}
export function initialize() {

View File

@ -1,11 +1,19 @@
import $ from "jquery";
import * as emoji from "../shared/js/emoji";
import render_set_status_overlay from "../templates/set_status_overlay.hbs";
import render_status_emoji_selector from "../templates/status_emoji_selector.hbs";
import * as overlays from "./overlays";
import * as people from "./people";
import * as user_status from "./user_status";
let selected_emoji_info = {};
export function set_selected_emoji_info(emoji_info) {
selected_emoji_info = {...emoji_info};
rebuild_status_emoji_selector_ui(selected_emoji_info);
}
export function input_field() {
return $("#set_user_status_modal input.user_status");
}
@ -15,13 +23,19 @@ export function submit_button() {
}
export function open_user_status_modal() {
const rendered_set_status_overlay = render_set_status_overlay();
const user_id = people.my_current_user_id();
const selected_emoji_info = user_status.get_status_emoji(user_id) || {};
const rendered_set_status_overlay = render_set_status_overlay({
default_status_messages_and_emoji_info,
selected_emoji_info,
});
$(".app").append(rendered_set_status_overlay);
overlays.open_modal("#set_user_status_modal", {autoremove: true});
const user_id = people.my_current_user_id();
const old_status_text = user_status.get_status_text(user_id);
const old_emoji_info = user_status.get_status_emoji(user_id) || {};
set_selected_emoji_info(old_emoji_info);
const field = input_field();
field.val(old_status_text);
field.trigger("select");
@ -40,15 +54,24 @@ export function submit_new_status() {
const user_id = people.my_current_user_id();
let old_status_text = user_status.get_status_text(user_id) || "";
old_status_text = old_status_text.trim();
const old_emoji_info = user_status.get_status_emoji(user_id) || {};
const new_status_text = input_field().val().trim();
if (old_status_text === new_status_text) {
if (
old_status_text === new_status_text &&
old_emoji_info.emoji_name === selected_emoji_info.emoji_name &&
old_emoji_info.reaction_type === selected_emoji_info.reaction_type &&
old_emoji_info.emoji_code === selected_emoji_info.emoji_code
) {
close_user_status_modal();
return;
}
user_status.server_update({
status_text: new_status_text,
emoji_name: selected_emoji_info.emoji_name || "",
emoji_code: selected_emoji_info.emoji_code || "",
reaction_type: selected_emoji_info.reaction_type || "",
success() {
close_user_status_modal();
},
@ -59,10 +82,16 @@ export function update_button() {
const user_id = people.my_current_user_id();
let old_status_text = user_status.get_status_text(user_id) || "";
old_status_text = old_status_text.trim();
const old_emoji_info = user_status.get_status_emoji(user_id) || {};
const new_status_text = input_field().val().trim();
const button = submit_button();
if (old_status_text === new_status_text) {
if (
old_status_text === new_status_text &&
old_emoji_info.emoji_name === selected_emoji_info.emoji_name &&
old_emoji_info.reaction_type === selected_emoji_info.reaction_type &&
old_emoji_info.emoji_code === selected_emoji_info.emoji_code
) {
button.prop("disabled", true);
} else {
button.prop("disabled", false);
@ -70,7 +99,7 @@ export function update_button() {
}
export function toggle_clear_message_button() {
if (input_field().val() !== "") {
if (input_field().val() !== "" || selected_emoji_info.emoji_name) {
$("#clear_status_message_button").prop("disabled", false);
} else {
$("#clear_status_message_button").prop("disabled", true);
@ -87,6 +116,15 @@ export function user_status_picker_open() {
return $("#set_user_status_modal").length !== 0;
}
function rebuild_status_emoji_selector_ui(selected_emoji_info) {
let selected_emoji = null;
if (selected_emoji_info && Object.keys(selected_emoji_info).length) {
selected_emoji = selected_emoji_info;
}
const rendered_status_emoji_selector = render_status_emoji_selector({selected_emoji});
$("#set_user_status_modal .status_emoji_wrapper").html(rendered_status_emoji_selector);
}
export function initialize() {
$("body").on("click", ".user-status-value", (event) => {
event.stopPropagation();
@ -115,6 +153,7 @@ export function initialize() {
$("body").on("click", "#clear_status_message_button", () => {
clear_message();
set_selected_emoji_info();
update_button();
});
}

View File

@ -217,7 +217,8 @@ on a dark background, and don't change the dark labels dark either. */
textarea,
.new-style .tab-switcher .ind-tab:not(.selected),
select,
.pill-container {
.pill-container,
.user_status_content_wrapper {
background-color: hsla(0, 0%, 0%, 0.2);
border-color: hsla(0, 0%, 0%, 0.6);
color: inherit;

View File

@ -97,8 +97,13 @@
.user-presence-link,
.user_sidebar_entry .selectable_sidebar_block {
display: flex;
overflow: hidden;
text-overflow: ellipsis;
.user-name {
overflow: hidden;
text-overflow: ellipsis;
}
}
.user_sidebar_entry .selectable_sidebar_block {
@ -109,6 +114,17 @@
.user-presence-link {
width: calc(100% - 24px);
.status_emoji {
height: 16px;
width: 16px;
/* We are setting minimum width here because when the user's name is very long,
emoji's width decreases and causes it to break. */
min-width: 16px;
margin-left: 4px;
margin-right: 4px;
top: 8px;
}
}
.my_user_status {

View File

@ -9,16 +9,51 @@
left: 50%;
transform: translate(-50%, -50%);
margin-left: 0;
/* We are setting a z-index so emoji popover can be visible on top of it. */
z-index: 105;
.user_status_content_wrapper {
display: flex;
border: 1px solid;
border-color: hsla(0, 0%, 0%, 0.6);
border-radius: 5px;
input.user_status {
width: 94%;
@media (width < $ml_min) {
width: 93%;
input.user_status {
width: 95%;
border: none;
background-color: transparent;
padding-right: 25px;
@media (width < $ml_min) {
width: 92%;
}
}
.status_emoji_wrapper {
height: 20px;
width: 22px;
padding: 4px 8px 4px 8px;
border-right: 1px solid;
border-color: inherit;
cursor: pointer;
.selected_emoji {
width: 18px;
height: 18px;
top: 4px;
cursor: pointer;
}
.smiley_icon {
display: block;
font-size: 18px;
position: relative;
top: 1px;
left: 2px;
&:hover {
text-decoration: none;
}
}
}
}
.user-status-options {
padding-top: 10px;
padding-top: 15px;
padding-left: 2px;
button.user-status-value:hover {

View File

@ -1,14 +1,19 @@
<div id="set_user_status_modal" class="modal modal-bg hide fade new-style" tabindex="-1" role="dialog" aria-labelledby="set_user_status_modal_label" aria-hidden="true">
<div id="set_user_status_modal" class="modal modal-bg hide fade new-style" role="dialog" aria-labelledby="set_user_status_modal_label" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close close-modal-btn" data-dismiss="modal" aria-label="{{t 'Close' }}"><span aria-hidden="true">&times;</span></button>
<h3 id="set_user_status_modal_label">{{t "Set status" }} </h3>
</div>
<div class="modal-body">
<label for="user_status">{{t "Status message" }}</label>
<input type="text" class="user_status" maxlength="60" />
<button type="button" class="btn clear_search_button" id="clear_status_message_button" disabled="disabled">
<i class="fa fa-remove" aria-hidden="true"></i>
</button>
<div class="user_status_content_wrapper">
<div class="status_emoji_wrapper tippy-zulip-tooltip" data-tippy-content="{{t 'Click to change' }}" data-tippy-placement="top" aria-label="{{t 'Click to change' }}" tabindex="0" id="selected_emoji">
{{> status_emoji_selector}}
</div>
<input type="text" class="user_status" maxlength="60"/>
<button type="button" class="btn clear_search_button" id="clear_status_message_button" disabled="disabled">
<i class="fa fa-remove" aria-hidden="true"></i>
</button>
</div>
<div class="user-status-options">
<button type="button" class="button no-style user-status-value">{{t "In a meeting" }}</button>
<button type="button" class="button no-style user-status-value">{{t "Commuting" }}</button>

View File

@ -0,0 +1,13 @@
{{#if selected_emoji}}
{{#if selected_emoji.emoji_alt_code}}
<div class="emoji_alt_code">&nbsp:{{selected_emoji.emoji_name}}:</div>
{{else}}
{{#if selected_emoji.url}}
<img src="{{selected_emoji.url}}" class="emoji selected_emoji" />
{{else}}
<div class="emoji selected_emoji emoji-{{selected_emoji.emoji_code}}"></div>
{{/if}}
{{/if}}
{{else}}
<a type="button" class="smiley_icon status_emoji show fa fa-smile-o"></a>
{{/if}}

View File

@ -5,9 +5,17 @@
href="{{href}}"
data-user-id="{{user_id}}"
data-name="{{name}}">
{{name}}
{{#if my_user_status}}
<span class="my_user_status">{{my_user_status}}</span>
<span class="user-name">{{name}}</span>
{{#if status_emoji_info}}
{{#if status_emoji_info.emoji_alt_code}}
<div class="emoji_alt_code">&nbsp:{{status_emoji_info.emoji_name}}:</div>
{{else}}
{{#if status_emoji_info.url}}
<img src="{{status_emoji_info.url}}" class="emoji status_emoji" />
{{else}}
<div class="emoji status_emoji emoji-{{status_emoji_info.emoji_code}}"></div>
{{/if}}
{{/if}}
{{/if}}
</a>
<span class="unread_count">{{#if num_unread}}{{num_unread}}{{/if}}</span>