Add user status on user profile icon (#33653)
* Add user status on user profile icon Currently unstyled & no tests * Style the user status icon * Update snapshot for avatar wrapper * More snapshot updates * add if braces * Split out user status functions to avoid circular dep which has the weird effect of just breaking jest's mocking. * type imports * Update imports * Update snapshot * Tests * baseline image * Just snapshot the component itself --------- Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
co-authored by
Michael Telatynski
parent
f65a53a174
commit
bb07f84e41
@@ -54,6 +54,29 @@
|
||||
}
|
||||
}
|
||||
|
||||
.avatarWrapper {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.statusEmoji {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
/* bottom edges aligned with the avatar */
|
||||
bottom: 0;
|
||||
/* center of circle on the right edge of the avatar */
|
||||
right: -10px;
|
||||
background-color: var(--cpd-color-bg-canvas-default);
|
||||
}
|
||||
|
||||
.triggerButton {
|
||||
border: none;
|
||||
background: none;
|
||||
|
||||
@@ -170,6 +170,12 @@ export const GuestOpen: Story = {
|
||||
tags: ["!dev", "!autodocs"],
|
||||
};
|
||||
|
||||
export const WithStatusEmoji: Story = {
|
||||
args: {
|
||||
statusEmoji: "🐹",
|
||||
},
|
||||
};
|
||||
|
||||
export const AllOptions: Story = {
|
||||
args: {
|
||||
displayName: "Alice",
|
||||
|
||||
@@ -13,7 +13,7 @@ import userEvent from "@testing-library/user-event";
|
||||
|
||||
import * as stories from "./UserMenu.stories.tsx";
|
||||
|
||||
const { Default, LongerName, Condensed, Guest, Open, NoAvatar } = composeStories(stories);
|
||||
const { Default, LongerName, Condensed, Guest, Open, NoAvatar, WithStatusEmoji } = composeStories(stories);
|
||||
|
||||
describe("UserMenu", () => {
|
||||
it("renders a button", async () => {
|
||||
@@ -28,6 +28,10 @@ describe("UserMenu", () => {
|
||||
const { container } = render(<Condensed />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
it("renders the status emoji when set", async () => {
|
||||
const { container } = render(<WithStatusEmoji />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
it("renders a menu", async () => {
|
||||
const { baseElement, getByRole } = render(<Default />);
|
||||
await userEvent.click(getByRole("button"));
|
||||
|
||||
@@ -50,6 +50,10 @@ export interface UserMenuViewSnapshot {
|
||||
* Account management URL if the user is using OIDC.
|
||||
*/
|
||||
manageAccountHref?: string;
|
||||
/**
|
||||
* The user status emoji to display, or undefined for no icon.
|
||||
*/
|
||||
statusEmoji?: string;
|
||||
/**
|
||||
* A set of actions that the user can perform from the menu.
|
||||
*/
|
||||
@@ -108,11 +112,15 @@ export type UserMenuViewProps = {
|
||||
};
|
||||
|
||||
export function UserMenuView({ vm, className }: UserMenuViewProps): JSX.Element {
|
||||
const { userId, displayName, avatarUrl, expanded, open, manageAccountHref, actions, showAvatar } = useViewModel(vm);
|
||||
const { userId, displayName, avatarUrl, expanded, open, manageAccountHref, actions, showAvatar, statusEmoji } =
|
||||
useViewModel(vm);
|
||||
const { translate: _t } = useI18n();
|
||||
const trigger = (
|
||||
<button className={styles.triggerButton} aria-label={_t("menus|user_menu|title")}>
|
||||
<Avatar id={userId} name={displayName} type="round" size="36px" src={avatarUrl} />
|
||||
<div className={styles.avatarWrapper}>
|
||||
<Avatar id={userId} name={displayName} type="round" size="36px" src={avatarUrl} />
|
||||
{statusEmoji && <span className={styles.statusEmoji}>{statusEmoji}</span>}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
|
||||
|
||||
+199
-119
@@ -14,25 +14,29 @@ exports[`UserMenu > renders a button 1`] = `
|
||||
id="radix-react-use-id-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
<div
|
||||
class="UserMenu-module_avatarWrapper"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<span
|
||||
class="_typography_6v6n8_153 _font-heading-sm-semibold_6v6n8_93"
|
||||
@@ -57,25 +61,29 @@ exports[`UserMenu > renders a button with a longer name 1`] = `
|
||||
id="radix-react-use-id-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
<div
|
||||
class="UserMenu-module_avatarWrapper"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<span
|
||||
class="_typography_6v6n8_153 _font-heading-sm-semibold_6v6n8_93"
|
||||
@@ -105,25 +113,29 @@ exports[`UserMenu > renders a guest menu 1`] = `
|
||||
id="radix-react-use-id-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="@guest:attendees.example.org"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="4"
|
||||
data-type="round"
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
<div
|
||||
class="UserMenu-module_avatarWrapper"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
<span
|
||||
aria-label="@guest:attendees.example.org"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="4"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<span
|
||||
class="_typography_6v6n8_153 _font-heading-sm-semibold_6v6n8_93"
|
||||
@@ -154,25 +166,29 @@ exports[`UserMenu > renders a menu 1`] = `
|
||||
id="radix-react-use-id-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
<div
|
||||
class="UserMenu-module_avatarWrapper"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<span
|
||||
class="_typography_6v6n8_153 _font-heading-sm-semibold_6v6n8_93"
|
||||
@@ -217,25 +233,29 @@ exports[`UserMenu > renders a menu without an avatar 1`] = `
|
||||
id="radix-react-use-id-2"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
<div
|
||||
class="UserMenu-module_avatarWrapper"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<span
|
||||
class="_typography_6v6n8_153 _font-heading-sm-semibold_6v6n8_93"
|
||||
@@ -526,25 +546,29 @@ exports[`UserMenu > renders an open menu 1`] = `
|
||||
id="radix-react-use-id-2"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
<div
|
||||
class="UserMenu-module_avatarWrapper"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<span
|
||||
class="_typography_6v6n8_153 _font-heading-sm-semibold_6v6n8_93"
|
||||
@@ -835,26 +859,82 @@ exports[`UserMenu > renders condensed view 1`] = `
|
||||
id="radix-react-use-id-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
<div
|
||||
class="UserMenu-module_avatarWrapper"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`UserMenu > renders the status emoji when set 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="UserMenu-module_wrapper"
|
||||
>
|
||||
<button
|
||||
aria-expanded="false"
|
||||
aria-haspopup="menu"
|
||||
aria-label="User menu"
|
||||
class="UserMenu-module_triggerButton"
|
||||
data-state="closed"
|
||||
id="radix-react-use-id-1"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="UserMenu-module_avatarWrapper"
|
||||
>
|
||||
<span
|
||||
aria-label="@person-name:homeserver.com"
|
||||
class="_avatar_va14e_8"
|
||||
data-color="1"
|
||||
data-type="round"
|
||||
role="img"
|
||||
style="--cpd-avatar-size: 36px;"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_va14e_43"
|
||||
data-type="round"
|
||||
height="36px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="/static/element.png"
|
||||
width="36px"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="UserMenu-module_statusEmoji"
|
||||
>
|
||||
🐹
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<span
|
||||
class="_typography_6v6n8_153 _font-heading-sm-semibold_6v6n8_93"
|
||||
>
|
||||
Sally Sanderson
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user