mirror of https://github.com/zulip/zulip.git
personal_menu: Add tippy personal_menu dropdown.
Add a personal menu dropdown that opens on clicking user avatar icon in navbar added in previous commit. The args passed to render_personal_menu() in onShow() are returned by get_personal_menu_content_context() in popover_menus_data.js so that they can be unit tested. Additionally, added CSS to get a custom arrow for dropdown menu. Added a `?` hotkey in keyboard shortcuts option in personal_menu dropdown in a style similar to our tooltip's hotkey by adding ? in a span with class .tooltip-hotkey-hint and adding some CSS. Fixes part of #22802.
This commit is contained in:
parent
5fd8b95454
commit
49f7f02a0a
|
@ -156,6 +156,7 @@ EXEMPT_FILES = make_set(
|
||||||
"web/src/overlays.ts",
|
"web/src/overlays.ts",
|
||||||
"web/src/padded_widget.ts",
|
"web/src/padded_widget.ts",
|
||||||
"web/src/page_params.ts",
|
"web/src/page_params.ts",
|
||||||
|
"web/src/personal_menu_popover.js",
|
||||||
"web/src/playground_links_popover.js",
|
"web/src/playground_links_popover.js",
|
||||||
"web/src/plotly.js.d.ts",
|
"web/src/plotly.js.d.ts",
|
||||||
"web/src/pm_list.js",
|
"web/src/pm_list.js",
|
||||||
|
|
|
@ -537,6 +537,12 @@ export async function open_streams_modal(page: Page): Promise<void> {
|
||||||
assert.ok(url.includes("#streams/all"));
|
assert.ok(url.includes("#streams/all"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function open_personal_menu(page: Page): Promise<void> {
|
||||||
|
const menu_selector = "#personal-menu";
|
||||||
|
await page.waitForSelector(menu_selector, {visible: true});
|
||||||
|
await page.click(menu_selector);
|
||||||
|
}
|
||||||
|
|
||||||
export async function manage_organization(page: Page): Promise<void> {
|
export async function manage_organization(page: Page): Promise<void> {
|
||||||
const menu_selector = "#settings-dropdown";
|
const menu_selector = "#settings-dropdown";
|
||||||
await page.waitForSelector(menu_selector, {visible: true});
|
await page.waitForSelector(menu_selector, {visible: true});
|
||||||
|
|
|
@ -19,9 +19,9 @@ async function open_menu(page: Page): Promise<void> {
|
||||||
async function navigate_to_settings(page: Page): Promise<void> {
|
async function navigate_to_settings(page: Page): Promise<void> {
|
||||||
console.log("Navigating to settings");
|
console.log("Navigating to settings");
|
||||||
|
|
||||||
await open_menu(page);
|
await common.open_personal_menu(page);
|
||||||
|
|
||||||
const settings_selector = ".dropdown-menu a[href^='#settings']";
|
const settings_selector = "#personal-menu-dropdown a[href^='#settings']";
|
||||||
await page.waitForSelector(settings_selector, {visible: true});
|
await page.waitForSelector(settings_selector, {visible: true});
|
||||||
await page.click(settings_selector);
|
await page.click(settings_selector);
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,9 @@ async function get_decoded_url_in_selector(page: Page, selector: string): Promis
|
||||||
}
|
}
|
||||||
|
|
||||||
async function open_settings(page: Page): Promise<void> {
|
async function open_settings(page: Page): Promise<void> {
|
||||||
const menu_selector = "#settings-dropdown";
|
await common.open_personal_menu(page);
|
||||||
await page.waitForSelector(menu_selector, {visible: true});
|
|
||||||
await page.click(menu_selector);
|
|
||||||
|
|
||||||
const settings_selector = '.dropdown-menu a[href="#settings"]';
|
const settings_selector = "#personal-menu-dropdown a[href^='#settings']";
|
||||||
await page.waitForSelector(settings_selector, {visible: true});
|
await page.waitForSelector(settings_selector, {visible: true});
|
||||||
await page.click(settings_selector);
|
await page.click(settings_selector);
|
||||||
|
|
||||||
|
|
|
@ -926,4 +926,10 @@ export function initialize() {
|
||||||
$(".settings-header.mobile .fa-chevron-left").on("click", () => {
|
$(".settings-header.mobile .fa-chevron-left").on("click", () => {
|
||||||
settings_panel_menu.mobile_deactivate_section();
|
settings_panel_menu.mobile_deactivate_section();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("body").on("click", ".trigger-natural-click", (e) => {
|
||||||
|
// Jquery prevents default action on anchor for `trigger("click")`
|
||||||
|
// so we need to use click on element to trigger the default action.
|
||||||
|
e.currentTarget.click();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
import $ from "jquery";
|
||||||
|
import tippy from "tippy.js";
|
||||||
|
|
||||||
|
import render_personal_menu from "../templates/personal_menu.hbs";
|
||||||
|
|
||||||
|
import * as gear_menu from "./gear_menu";
|
||||||
|
import * as narrow from "./narrow";
|
||||||
|
import {page_params} from "./page_params";
|
||||||
|
import * as people from "./people";
|
||||||
|
import * as popover_menus from "./popover_menus";
|
||||||
|
import * as popover_menus_data from "./popover_menus_data";
|
||||||
|
import * as popovers from "./popovers";
|
||||||
|
import {parse_html} from "./ui_util";
|
||||||
|
import * as user_profile from "./user_profile";
|
||||||
|
import * as user_status from "./user_status";
|
||||||
|
|
||||||
|
function elem_to_user_id($elem) {
|
||||||
|
return Number.parseInt($elem.attr("data-user-id"), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initialize() {
|
||||||
|
popover_menus.register_popover_menu("#personal-menu", {
|
||||||
|
placement: "bottom",
|
||||||
|
offset: [-50, 0],
|
||||||
|
// The strategy: "fixed"; and eventlisteners modifier option
|
||||||
|
// ensure that the personal menu does not modify its position
|
||||||
|
// or disappear when user zooms the page.
|
||||||
|
popperOptions: {
|
||||||
|
strategy: "fixed",
|
||||||
|
modifiers: [
|
||||||
|
{
|
||||||
|
name: "eventListeners",
|
||||||
|
options: {
|
||||||
|
scroll: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
onMount(instance) {
|
||||||
|
const $popper = $(instance.popper);
|
||||||
|
$popper.addClass("personal-menu-tippy");
|
||||||
|
popover_menus.popover_instances.personal_menu = instance;
|
||||||
|
|
||||||
|
// Workaround for the gear menu not being a tippy popover
|
||||||
|
// and thus not auto-closing.
|
||||||
|
gear_menu.close();
|
||||||
|
|
||||||
|
tippy(".clear_status", {
|
||||||
|
placement: "top",
|
||||||
|
appendTo: document.body,
|
||||||
|
interactive: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
$popper.one("click", ".clear_status", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const me = page_params.user_id;
|
||||||
|
user_status.server_update_status({
|
||||||
|
user_id: me,
|
||||||
|
status_text: "",
|
||||||
|
emoji_name: "",
|
||||||
|
emoji_code: "",
|
||||||
|
success() {
|
||||||
|
instance.hide();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$popper.one("click", ".personal-menu-actions .view_full_user_profile", (e) => {
|
||||||
|
const user_id = elem_to_user_id($(e.target).closest(".personal-menu-actions"));
|
||||||
|
const user = people.get_by_user_id(user_id);
|
||||||
|
popovers.hide_all();
|
||||||
|
user_profile.show_user_profile(user);
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
$popper.one("click", ".narrow-self-direct-message", (e) => {
|
||||||
|
const user_id = page_params.user_id;
|
||||||
|
const email = people.get_by_user_id(user_id).email;
|
||||||
|
narrow.by("dm", email, {trigger: "personal menu"});
|
||||||
|
popovers.hide_all();
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
$popper.one("click", ".narrow-messages-sent", (e) => {
|
||||||
|
const user_id = page_params.user_id;
|
||||||
|
const email = people.get_by_user_id(user_id).email;
|
||||||
|
narrow.by("sender", email, {trigger: "personal menu"});
|
||||||
|
popovers.hide_all();
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
$popper.one("click", ".open-profile-settings", (e) => {
|
||||||
|
e.currentTarget.click();
|
||||||
|
popovers.hide_all();
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".focus-dropdown").on("focus", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
$popper.find("li:visible a").eq(0).trigger("focus");
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.popperInstance.update();
|
||||||
|
},
|
||||||
|
onShow(instance) {
|
||||||
|
const args = popover_menus_data.get_personal_menu_content_context();
|
||||||
|
instance.setContent(parse_html(render_personal_menu(args)));
|
||||||
|
},
|
||||||
|
onHidden(instance) {
|
||||||
|
instance.destroy();
|
||||||
|
popover_menus.popover_instances.personal_menu = undefined;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ export const popover_instances = {
|
||||||
topics_menu: null,
|
topics_menu: null,
|
||||||
send_later: null,
|
send_later: null,
|
||||||
change_visibility_policy: null,
|
change_visibility_policy: null,
|
||||||
|
personal_menu: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Keyboard UI functions */
|
/* Keyboard UI functions */
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
import * as resolved_topic from "../shared/src/resolved_topic";
|
import * as resolved_topic from "../shared/src/resolved_topic";
|
||||||
|
|
||||||
|
import * as buddy_data from "./buddy_data";
|
||||||
import * as hash_util from "./hash_util";
|
import * as hash_util from "./hash_util";
|
||||||
import {$t} from "./i18n";
|
import {$t} from "./i18n";
|
||||||
import * as message_edit from "./message_edit";
|
import * as message_edit from "./message_edit";
|
||||||
|
@ -10,10 +11,13 @@ import * as message_lists from "./message_lists";
|
||||||
import * as muted_users from "./muted_users";
|
import * as muted_users from "./muted_users";
|
||||||
import * as narrow_state from "./narrow_state";
|
import * as narrow_state from "./narrow_state";
|
||||||
import {page_params} from "./page_params";
|
import {page_params} from "./page_params";
|
||||||
|
import * as people from "./people";
|
||||||
import * as settings_data from "./settings_data";
|
import * as settings_data from "./settings_data";
|
||||||
import * as starred_messages from "./starred_messages";
|
import * as starred_messages from "./starred_messages";
|
||||||
import * as stream_data from "./stream_data";
|
import * as stream_data from "./stream_data";
|
||||||
import * as sub_store from "./sub_store";
|
import * as sub_store from "./sub_store";
|
||||||
|
import {user_settings} from "./user_settings";
|
||||||
|
import * as user_status from "./user_status";
|
||||||
import * as user_topics from "./user_topics";
|
import * as user_topics from "./user_topics";
|
||||||
|
|
||||||
export function get_actions_popover_content_context(message_id) {
|
export function get_actions_popover_content_context(message_id) {
|
||||||
|
@ -154,3 +158,30 @@ export function get_change_visibility_policy_popover_content_context(stream_id,
|
||||||
all_visibility_policies,
|
all_visibility_policies,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function get_personal_menu_content_context() {
|
||||||
|
const my_user_id = page_params.user_id;
|
||||||
|
const invisible_mode = !user_settings.presence_enabled;
|
||||||
|
const status_text = user_status.get_status_text(my_user_id);
|
||||||
|
const status_emoji_info = user_status.get_status_emoji(my_user_id);
|
||||||
|
return {
|
||||||
|
user_id: my_user_id,
|
||||||
|
invisible_mode,
|
||||||
|
user_is_guest: page_params.is_guest,
|
||||||
|
spectator_view: page_params.is_spectator,
|
||||||
|
|
||||||
|
// user information
|
||||||
|
user_avatar: page_params.avatar_url_medium,
|
||||||
|
is_active: people.is_active_user_for_popover(my_user_id),
|
||||||
|
user_circle_class: buddy_data.get_user_circle_class(my_user_id),
|
||||||
|
user_last_seen_time_status: buddy_data.user_last_seen_time_status(my_user_id),
|
||||||
|
user_full_name: page_params.full_name,
|
||||||
|
user_type: people.get_user_type(my_user_id),
|
||||||
|
|
||||||
|
// user status
|
||||||
|
status_content_available: Boolean(status_text || status_emoji_info),
|
||||||
|
status_text,
|
||||||
|
status_emoji_info,
|
||||||
|
user_time: people.get_user_time(my_user_id),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -194,6 +194,7 @@ export function initialize() {
|
||||||
"#add_streams_tooltip",
|
"#add_streams_tooltip",
|
||||||
"#filter_streams_tooltip",
|
"#filter_streams_tooltip",
|
||||||
".error-icon-message-recipient .zulip-icon",
|
".error-icon-message-recipient .zulip-icon",
|
||||||
|
"#personal-menu-dropdown .status-circle",
|
||||||
],
|
],
|
||||||
appendTo: () => document.body,
|
appendTo: () => document.body,
|
||||||
});
|
});
|
||||||
|
|
|
@ -79,6 +79,7 @@ import * as navigate from "./navigate";
|
||||||
import * as overlays from "./overlays";
|
import * as overlays from "./overlays";
|
||||||
import {page_params} from "./page_params";
|
import {page_params} from "./page_params";
|
||||||
import * as people from "./people";
|
import * as people from "./people";
|
||||||
|
import * as personal_menu_popover from "./personal_menu_popover";
|
||||||
import * as playground_links_popover from "./playground_links_popover";
|
import * as playground_links_popover from "./playground_links_popover";
|
||||||
import * as pm_conversations from "./pm_conversations";
|
import * as pm_conversations from "./pm_conversations";
|
||||||
import * as pm_list from "./pm_list";
|
import * as pm_list from "./pm_list";
|
||||||
|
@ -709,6 +710,7 @@ export function initialize_everything() {
|
||||||
user_group_popover.initialize();
|
user_group_popover.initialize();
|
||||||
user_card_popover.initialize();
|
user_card_popover.initialize();
|
||||||
playground_links_popover.initialize();
|
playground_links_popover.initialize();
|
||||||
|
personal_menu_popover.initialize();
|
||||||
pm_list.initialize();
|
pm_list.initialize();
|
||||||
topic_list.initialize({
|
topic_list.initialize({
|
||||||
on_topic_click(stream_id, topic) {
|
on_topic_click(stream_id, topic) {
|
||||||
|
|
|
@ -118,6 +118,7 @@ export const update_person = function update(person) {
|
||||||
page_params.avatar_url = url;
|
page_params.avatar_url = url;
|
||||||
page_params.avatar_url_medium = person.avatar_url_medium;
|
page_params.avatar_url_medium = person.avatar_url_medium;
|
||||||
$("#user-avatar-upload-widget .image-block").attr("src", person.avatar_url_medium);
|
$("#user-avatar-upload-widget .image-block").attr("src", person.avatar_url_medium);
|
||||||
|
$("#personal-menu .header-button-avatar").attr("src", `${person.avatar_url_medium}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
message_live_update.update_avatar(person_obj.user_id, person.avatar_url);
|
message_live_update.update_avatar(person_obj.user_id, person.avatar_url);
|
||||||
|
|
|
@ -1033,3 +1033,161 @@ ul {
|
||||||
border: 1px solid hsl(0deg 0% 0% / 20%);
|
border: 1px solid hsl(0deg 0% 0% / 20%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.personal-menu-header {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
gap: 7px;
|
||||||
|
text-align: left;
|
||||||
|
padding: 4px;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
position: relative;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-image {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-circle {
|
||||||
|
position: absolute;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
top: unset;
|
||||||
|
left: unset;
|
||||||
|
right: -1px;
|
||||||
|
bottom: -1px;
|
||||||
|
border: solid 1px var(--color-background);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user_circle_empty {
|
||||||
|
background-color: var(--color-background-dropdown-menu);
|
||||||
|
border-color: hsl(0deg 0% 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-area {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-top: 4px;
|
||||||
|
|
||||||
|
& p {
|
||||||
|
margin: 0 0 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-name {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 20px;
|
||||||
|
color: var(--color-text-full-name) !important;
|
||||||
|
max-width: 150px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-type {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px;
|
||||||
|
color: var(--color-text-item) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.personal-menu-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
|
||||||
|
.list {
|
||||||
|
margin: 0;
|
||||||
|
padding: 4px 0;
|
||||||
|
list-style: none;
|
||||||
|
border-bottom: solid 1px var(--color-border-popover-menu);
|
||||||
|
background: none !important;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-item,
|
||||||
|
.link-item a {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 16px;
|
||||||
|
|
||||||
|
& i {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-item {
|
||||||
|
color: var(--color-text-item);
|
||||||
|
width: auto;
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-item {
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
background: var(--color-background-hover-dropdown-menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
& i {
|
||||||
|
color: var(--color-icon-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
& a {
|
||||||
|
color: var(--color-text-dropdown-menu) !important;
|
||||||
|
text-decoration: none;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
flex-grow: 1;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--color-background-hover-dropdown-menu);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-radius: 4px;
|
||||||
|
/* Override the default focus style */
|
||||||
|
outline: 1px solid var(--color-outline-focus) !important;
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: var(--color-background-active-dropdown-menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear_status {
|
||||||
|
margin-left: auto;
|
||||||
|
color: hsl(0deg 0% 40%) !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status_emoji {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -197,6 +197,14 @@ body {
|
||||||
--color-search-shadow-tight: hsl(0deg 0% 0% / 10%);
|
--color-search-shadow-tight: hsl(0deg 0% 0% / 10%);
|
||||||
--color-search-dropdown-top-border: hsla(0deg 0% 0% / 10%);
|
--color-search-dropdown-top-border: hsla(0deg 0% 0% / 10%);
|
||||||
--color-background-image-loader: hsl(0deg 0% 0% / 10%);
|
--color-background-image-loader: hsl(0deg 0% 0% / 10%);
|
||||||
|
--color-icon-purple: hsl(240deg 35% 60%);
|
||||||
|
--color-background-dropdown-menu: hsl(0deg 0% 100%);
|
||||||
|
--color-border-popover-menu: hsl(0deg 0% 0% / 10%);
|
||||||
|
--color-hotkey-hint: hsl(227deg 78% 59%);
|
||||||
|
--color-background-hover-dropdown-menu: hsl(220deg 12% 5% / 5%);
|
||||||
|
--color-background-active-dropdown-menu: hsl(220deg 12% 5% / 7%);
|
||||||
|
--color-border-dropdown-menu: hsl(0deg 0% 0% / 40%);
|
||||||
|
--color-border-personal-menu-avatar: hsl(0deg 0% 0% / 10%);
|
||||||
--color-background-unread-counter: hsl(105deg 2% 50%);
|
--color-background-unread-counter: hsl(105deg 2% 50%);
|
||||||
--color-background-unread-counter-popover-menu: hsl(200deg 100% 40%);
|
--color-background-unread-counter-popover-menu: hsl(200deg 100% 40%);
|
||||||
|
|
||||||
|
@ -228,6 +236,9 @@ body {
|
||||||
--color-text-search: hsl(0deg 0% 35%);
|
--color-text-search: hsl(0deg 0% 35%);
|
||||||
--color-text-search-hover: hsl(0deg 0% 0%);
|
--color-text-search-hover: hsl(0deg 0% 0%);
|
||||||
--color-text-search-placeholder: hsl(0deg 0% 50%);
|
--color-text-search-placeholder: hsl(0deg 0% 50%);
|
||||||
|
--color-text-dropdown-menu: hsl(0deg 0% 15%);
|
||||||
|
--color-text-full-name: hsl(0deg 0% 15%);
|
||||||
|
--color-text-item: hsl(0deg 0% 40%);
|
||||||
|
|
||||||
/* Icon colors */
|
/* Icon colors */
|
||||||
--color-icon-bot: hsl(180deg 8% 65% / 100%);
|
--color-icon-bot: hsl(180deg 8% 65% / 100%);
|
||||||
|
@ -312,6 +323,13 @@ body {
|
||||||
--color-search-box-hover-shadow: hsl(0deg 0% 0% / 30%);
|
--color-search-box-hover-shadow: hsl(0deg 0% 0% / 30%);
|
||||||
--color-search-dropdown-top-border: hsla(0deg 0% 0% / 35%);
|
--color-search-dropdown-top-border: hsla(0deg 0% 0% / 35%);
|
||||||
--color-background-image-loader: hsl(0deg 0% 100% / 10%);
|
--color-background-image-loader: hsl(0deg 0% 100% / 10%);
|
||||||
|
--color-background-dropdown-menu: hsl(0deg 0% 17%);
|
||||||
|
--color-border-popover-menu: hsl(0deg 0% 0% / 40%);
|
||||||
|
--color-hotkey-hint: hsl(225deg 100% 84%);
|
||||||
|
--color-background-hover-dropdown-menu: hsl(220deg 12% 95% / 5%);
|
||||||
|
--color-background-active-dropdown-menu: hsl(220deg 12% 95% / 7%);
|
||||||
|
--color-border-dropdown-menu: hsl(0deg 0% 0%);
|
||||||
|
--color-border-personal-menu-avatar: hsl(0deg 0% 100% / 20%);
|
||||||
--color-background-unread-counter: hsl(105deg 2% 50% / 50%);
|
--color-background-unread-counter: hsl(105deg 2% 50% / 50%);
|
||||||
--color-background-unread-counter-popover-menu: hsl(105deg 2% 50% / 50%);
|
--color-background-unread-counter-popover-menu: hsl(105deg 2% 50% / 50%);
|
||||||
|
|
||||||
|
@ -349,6 +367,9 @@ body {
|
||||||
--color-text-search: hsl(0deg 0% 100% / 75%);
|
--color-text-search: hsl(0deg 0% 100% / 75%);
|
||||||
--color-text-search-hover: hsl(0deg 0% 100%);
|
--color-text-search-hover: hsl(0deg 0% 100%);
|
||||||
--color-text-search-placeholder: hsl(0deg 0% 100% / 50%);
|
--color-text-search-placeholder: hsl(0deg 0% 100% / 50%);
|
||||||
|
--color-text-dropdown-menu: hsl(0deg 0% 100% / 80%);
|
||||||
|
--color-text-full-name: hsl(0deg 0% 100%);
|
||||||
|
--color-text-item: hsl(0deg 0% 50%);
|
||||||
|
|
||||||
/* Icon colors */
|
/* Icon colors */
|
||||||
--color-icon-bot: hsl(180deg 5% 50% / 100%);
|
--color-icon-bot: hsl(180deg 5% 50% / 100%);
|
||||||
|
@ -3451,5 +3472,74 @@ select.invite-as {
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: var(--color-background-image-loader);
|
background-color: var(--color-background-image-loader);
|
||||||
|
border: 1px solid var(--color-border-personal-menu-avatar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#personal-menu-dropdown {
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
border: solid 1px var(--color-border-dropdown-menu);
|
||||||
|
background-color: var(--color-background-dropdown-menu);
|
||||||
|
max-height: 85vh;
|
||||||
|
min-width: 230px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
.simplebar-content {
|
||||||
|
min-width: max-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.personal-menu-tippy {
|
||||||
|
.tippy-box {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tippy-content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .tippy-box > .tippy-arrow {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: -5.5px !important;
|
||||||
|
width: 16px;
|
||||||
|
height: 8px;
|
||||||
|
z-index: 1;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
filter: drop-shadow(0 -1.25px 0 var(--color-border-dropdown-menu));
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: 0 !important;
|
||||||
|
content: "";
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
mask-image: url("../shared/icons/popover-arrow.svg");
|
||||||
|
mask-size: contain;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
background-color: var(--color-background-dropdown-menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.keyboard-shortcut-option {
|
||||||
|
& span.tooltip-hotkey-hint {
|
||||||
|
margin-left: auto;
|
||||||
|
padding: 0 4px;
|
||||||
|
color: var(--color-hotkey-hint);
|
||||||
|
border-color: var(--color-hotkey-hint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
<a class="header-button tippy-zulip-delayed-tooltip" tabindex="0" role="button" data-tippy-content="{{t 'Personal menu' }}">
|
<a class="header-button tippy-zulip-delayed-tooltip" tabindex="0" role="button" data-tippy-content="{{t 'Personal menu' }}">
|
||||||
<img class="header-button-avatar" src="{{user_avatar}}"/>
|
<img class="header-button-avatar" src="{{user_avatar}}"/>
|
||||||
</a>
|
</a>
|
||||||
|
<span tabindex="0" class="focus-dropdown"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
<div class="dropdown-menu" id="personal-menu-dropdown" data-simplebar>
|
||||||
|
<nav class="inner">
|
||||||
|
<header class="personal-menu-header">
|
||||||
|
<div class="avatar">
|
||||||
|
<img class="avatar-image{{#if user_is_guest}} guest-avatar{{/if}}" src="{{user_avatar}}"/>
|
||||||
|
|
||||||
|
{{#if is_active }}
|
||||||
|
<span class="status-circle {{user_circle_class}} user_circle hidden-for-spectators" data-tippy-placement="bottom" data-tippy-content="{{user_last_seen_time_status}}"></span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="text-area">
|
||||||
|
<p class="full-name">{{user_full_name}}</p>
|
||||||
|
<p class="user-type">{{user_type}}</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<section class="popover-menu personal-menu-actions" data-user-id="{{user_id}}">
|
||||||
|
<ul class="list">
|
||||||
|
<li class="text-item hidden-for-spectators">
|
||||||
|
<i class="zulip-icon zulip-icon-clock"></i>
|
||||||
|
{{#tr}}{user_time} local time{{/tr}}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="list">
|
||||||
|
{{#if status_content_available}}
|
||||||
|
<li class="text-item">
|
||||||
|
<span>
|
||||||
|
{{#if status_emoji_info}}
|
||||||
|
{{#if status_emoji_info.emoji_alt_code}}
|
||||||
|
<span class="emoji_alt_code"> :{{status_emoji_info.emoji_name}}:</span>
|
||||||
|
{{else if status_emoji_info.url}}
|
||||||
|
<img src="{{status_emoji_info.url}}" class="emoji status_emoji" />
|
||||||
|
{{else}}
|
||||||
|
<span class="emoji status_emoji emoji-{{status_emoji_info.emoji_code}}"></span>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
<span class="status_text">
|
||||||
|
{{status_text}}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<a href="" class="clear_status" aria-label="{{t 'Clear status'}}" data-tippy-content="{{t 'Clear your status' }}">
|
||||||
|
<i class="zulip-icon zulip-icon-x-circle"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="link-item">
|
||||||
|
<a href="" class="update_status_text">
|
||||||
|
<i class="zulip-icon zulip-icon-smile"></i>
|
||||||
|
{{#tr}}Edit status{{/tr}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{else}}
|
||||||
|
<li class="link-item hidden-for-spectators">
|
||||||
|
<a href="" class="update_status_text">
|
||||||
|
<i class="zulip-icon zulip-icon-smile"></i>
|
||||||
|
{{#tr}}Set status{{/tr}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if invisible_mode}}
|
||||||
|
<li class="link-item hidden-for-spectators">
|
||||||
|
<a href="" class="invisible_mode_turn_off">
|
||||||
|
<i class="zulip-icon zulip-icon-play-circle"></i>
|
||||||
|
{{#tr}}Turn off invisible mode{{/tr}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{else}}
|
||||||
|
<li class="link-item hidden-for-spectators">
|
||||||
|
<a href="" class="invisible_mode_turn_on">
|
||||||
|
<i class="zulip-icon zulip-icon-stop-circle"></i>
|
||||||
|
{{#tr}}Go invisible{{/tr}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/if}}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="list">
|
||||||
|
<li class="link-item">
|
||||||
|
<a tabindex="0" class="view_full_user_profile">
|
||||||
|
<i class="zulip-icon zulip-icon-account"></i>
|
||||||
|
{{#tr}}View your profile{{/tr}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="link-item">
|
||||||
|
<a href="" class="narrow-self-direct-message">
|
||||||
|
<i class="zulip-icon zulip-icon-users"></i>
|
||||||
|
{{#tr}}View messages with yourself{{/tr}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="link-item">
|
||||||
|
<a href="" class="narrow-messages-sent">
|
||||||
|
<i class="zulip-icon zulip-icon-message-square"></i>
|
||||||
|
{{#tr}}View messages sent{{/tr}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul class="list">
|
||||||
|
<li class="link-item">
|
||||||
|
<a href="#settings/profile" class="open-profile-settings">
|
||||||
|
<i class="zulip-icon zulip-icon-tool"></i>
|
||||||
|
{{#tr}}Settings{{/tr}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="list">
|
||||||
|
<li class="link-item" role="presentation">
|
||||||
|
<a class="logout_button hidden-for-spectators" tabindex="0">
|
||||||
|
<i class="zulip-icon zulip-icon-power" aria-hidden="true"></i>
|
||||||
|
{{t 'Log out' }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</nav>
|
||||||
|
</div>
|
|
@ -5,6 +5,7 @@ const {strict: assert} = require("assert");
|
||||||
const {mock_esm, zrequire} = require("./lib/namespace");
|
const {mock_esm, zrequire} = require("./lib/namespace");
|
||||||
const {run_test} = require("./lib/test");
|
const {run_test} = require("./lib/test");
|
||||||
const blueslip = require("./lib/zblueslip");
|
const blueslip = require("./lib/zblueslip");
|
||||||
|
const $ = require("./lib/zjquery");
|
||||||
const {page_params} = require("./lib/zpage_params");
|
const {page_params} = require("./lib/zpage_params");
|
||||||
|
|
||||||
const message_live_update = mock_esm("../src/message_live_update");
|
const message_live_update = mock_esm("../src/message_live_update");
|
||||||
|
@ -206,6 +207,8 @@ run_test("updates", () => {
|
||||||
assert.equal(user_id, isaac.user_id);
|
assert.equal(user_id, isaac.user_id);
|
||||||
assert.equal(person.avatar_url, avatar_url);
|
assert.equal(person.avatar_url, avatar_url);
|
||||||
|
|
||||||
|
$("#personal-menu .header-button-avatar").css = () => {};
|
||||||
|
|
||||||
user_events.update_person({user_id: me.user_id, avatar_url: "http://gravatar.com/789456"});
|
user_events.update_person({user_id: me.user_id, avatar_url: "http://gravatar.com/789456"});
|
||||||
person = people.get_by_email(me.email);
|
person = people.get_by_email(me.email);
|
||||||
assert.equal(person.full_name, "Me V2");
|
assert.equal(person.full_name, "Me V2");
|
||||||
|
|
Loading…
Reference in New Issue