@nextcloud/vue
Version:
Nextcloud vue components
841 lines (840 loc) • 28.2 kB
JavaScript
import '../assets/NcAvatar.css';
import { getCurrentUser } from "@nextcloud/auth";
import axios from "@nextcloud/axios";
import { getBuilder } from "@nextcloud/browser-storage";
import { unsubscribe, subscribe } from "@nextcloud/event-bus";
import { generateOcsUrl, generateUrl } from "@nextcloud/router";
import { vOnClickOutside } from "@vueuse/components";
import debounce from "debounce";
import { defineAsyncComponent, resolveComponent, resolveDirective, withDirectives, openBlock, createElementBlock, normalizeStyle, normalizeClass, renderSlot, createCommentVNode, Fragment, createBlock, withCtx, createSlots, renderList, resolveDynamicComponent, mergeProps, createTextVNode, toDisplayString, createVNode, createElementVNode } from "vue";
import { N as NcActions, I as IconDotsHorizontal } from "./NcActions.mjs";
import { g as getRoute } from "./autolink.mjs";
import "../composables/useFormatDateTime/index.mjs";
import "../composables/useHotKey/index.mjs";
import { useIsDarkTheme } from "../composables/useIsDarkTheme/index.mjs";
import "../composables/useIsFullscreen/index.mjs";
import "../composables/useIsMobile/index.mjs";
import { getEnabledContactsMenuActions } from "../functions/contactsMenu/index.mjs";
import { usernameToColor } from "../functions/usernameToColor/index.mjs";
import { r as register, n as t11, a as t } from "./_l10n.mjs";
import "escape-html";
import "striptags";
import { g as getAvatarUrl } from "./NcMentionBubble.vue_vue_type_style_index_0_scoped_3c4a673d_lang.mjs";
import { _ as _export_sfc } from "./_plugin-vue_export-helper.mjs";
import { getCapabilities } from "@nextcloud/capabilities";
import { l as logger } from "./logger.mjs";
import { b as isLegacy35 } from "./legacy.mjs";
import { N as NcUserStatusIcon, g as getUserStatusText } from "./NcUserStatusIcon.mjs";
import { N as NcActionButton } from "./NcActionButton.mjs";
import { N as NcActionLink } from "./NcActionLink.mjs";
import { N as NcActionRouter } from "./NcActionRouter.mjs";
import { N as NcActionText } from "./NcActionText.mjs";
import { N as NcButton } from "./NcButton.mjs";
import { N as NcIconSvgWrapper } from "./NcIconSvgWrapper.mjs";
import { N as NcLoadingIcon } from "./NcLoadingIcon.mjs";
import { N as NcPopover } from "./NcPopover.mjs";
register(t11);
const userStatus = {
data() {
return {
hasStatus: false,
userStatus: {
status: null,
message: null,
icon: null
}
};
},
methods: {
/**
* Fetches the user-status from the server
*
* @param {string} userId UserId of the user to fetch the status for
*
* @return {Promise<void>}
*/
async fetchUserStatus(userId) {
if (!userId) {
return;
}
const capabilities = getCapabilities();
if (!Object.hasOwn(capabilities, "user_status") || !capabilities.user_status.enabled) {
return;
}
if (!getCurrentUser()) {
return;
}
try {
const { data } = await axios.get(generateOcsUrl("apps/user_status/api/v1/statuses/{userId}", { userId }));
this.setUserStatus(data.ocs.data);
} catch (e) {
if (e.response.status === 404 && e.response.data.ocs?.data?.length === 0) {
return;
}
logger.error("Failed to fetch user status", { error: e });
}
},
/**
* Sets the user status
*
* @param {Record<string, string>} options - Options for setting the user status
* @param {string} options.status user's status
* @param {string} options.message user's message
* @param {string} options.icon user's icon
*/
setUserStatus({ status, message, icon }) {
this.userStatus.status = status || "";
this.userStatus.message = message || "";
this.userStatus.icon = icon || "";
this.hasStatus = !!status;
}
}
};
const browserStorage = getBuilder("nextcloud").persist().build();
const SMALL_VARIANT_UPSCALE = 1.5;
function density(value) {
return Number(value.toFixed(3));
}
function getUserHasAvatar(userId) {
const flag = browserStorage.getItem("user-has-avatar." + userId);
if (typeof flag === "string") {
return Boolean(flag);
}
return null;
}
function setUserHasAvatar(userId, flag) {
if (userId) {
browserStorage.setItem("user-has-avatar." + userId, flag);
}
}
const _sfc_main = {
name: "NcAvatar",
directives: {
/** @type {import('vue').ObjectDirective} */
ClickOutside: vOnClickOutside
},
components: {
IconDotsHorizontal,
NcActions,
NcButton,
NcIconSvgWrapper,
NcLoadingIcon,
NcPopover,
NcProfileHoverCard: defineAsyncComponent(() => import("./NcProfileHoverCard.mjs")),
NcUserStatusIcon
},
mixins: [userStatus],
props: {
/**
* Set a custom url to the avatar image
* either the url, user or displayName property must be defined
*/
url: {
type: String,
default: void 0
},
/**
* Set a css icon-class for an icon to be used instead of the avatar.
*/
iconClass: {
type: String,
default: void 0
},
/**
* Set the user id to fetch the avatar
* either the url, user or displayName property must be defined
*/
user: {
type: String,
default: void 0
},
/**
* Do not show the user status on the avatar.
*/
hideStatus: {
type: Boolean,
default: false
},
/**
* Show the verbose user status (e.g. "online" / "away") instead of just the status icon.
*/
verboseStatus: {
type: Boolean,
default: false
},
/**
* When the user status was preloaded via another source it can be handed in with this property to save the request.
* If this property is not set the status will be fetched automatically.
* If a preloaded no-status is available provide this object with properties "status", "icon" and "message" set to null.
*/
preloadedUserStatus: {
type: Object,
default: void 0
},
/**
* Is the user a guest user (then we have to user a different endpoint)
*/
isGuest: {
type: Boolean,
default: false
},
/**
* The user's avatar version, as returned alongside user lists.
* Passing it earns the avatar a much longer cache lifetime.
*/
version: {
type: [String, Number],
default: void 0
},
/**
* Set a display name that will be rendered as a tooltip
* either the url, user or displayName property must be defined
* specify just the displayname to generate a placeholder avatar without
* trying to fetch the avatar based on the user id
*/
displayName: {
type: String,
default: void 0
},
/**
* Set a size in px for the rendered avatar
*/
size: {
type: Number,
default: 32
},
/**
* Do not automatically generate a placeholder avatars if there is no real avatar is available.
*/
noPlaceholder: {
type: Boolean,
default: false
},
/**
* Disable the tooltip
*/
disableTooltip: {
type: Boolean,
default: false
},
/**
* Disable the menu
*/
disableMenu: {
type: Boolean,
default: false
},
/**
* Declares a custom tooltip when not null
* Fallback will be the displayName
*
* requires disableTooltip not to be set to true
*/
tooltipMessage: {
type: String,
default: null
},
/**
* Declares username is not a user's name, when true.
* Prevents loading user's avatar from server and forces generating colored initials,
* i.e. if the user is a group
*/
isNoUser: {
type: Boolean,
default: false
},
/**
* Selector for the popover menu container
*/
menuContainer: {
type: [Boolean, String],
default: "body"
}
},
setup() {
const isDarkTheme = useIsDarkTheme();
return {
isDarkTheme,
isLegacy35
};
},
data() {
return {
avatarUrlLoaded: null,
avatarSrcSetLoaded: null,
userDoesNotExist: false,
isAvatarLoaded: false,
isMenuLoaded: false,
contactsMenuLoading: false,
contactsMenuData: {},
contactsMenuActions: [],
contactsMenuOpenState: false
};
},
computed: {
avatarAriaLabel() {
if (!this.hasMenu) {
return;
}
if (this.canDisplayUserStatus || this.showUserStatusIconOnAvatar) {
return t("Avatar of {displayName}, {status}", { displayName: this.displayName ?? this.user, status: getUserStatusText(this.userStatus.status) });
}
return t("Avatar of {displayName}", { displayName: this.displayName ?? this.user });
},
canDisplayUserStatus() {
return !this.hideStatus && this.hasStatus && ["online", "away", "busy", "dnd"].includes(this.userStatus.status);
},
showUserStatusIconOnAvatar() {
return !this.hideStatus && !this.verboseStatus && this.hasStatus && this.userStatus.status !== "dnd" && this.userStatus.icon;
},
/**
* The user identifier, either the display name if set or the user property
* If both properties are not set an empty string is returned
*/
userIdentifier() {
if (this.isDisplayNameDefined) {
return this.displayName;
}
if (this.isUserDefined) {
return this.user;
}
return "";
},
isUserDefined() {
return typeof this.user !== "undefined";
},
isDisplayNameDefined() {
return typeof this.displayName !== "undefined";
},
isUrlDefined() {
return typeof this.url !== "undefined";
},
hasMenu() {
if (this.disableMenu) {
return false;
}
if (this.isLegacy35) {
if (this.isMenuLoaded) {
return this.menu.length > 0;
}
return !(this.user === getCurrentUser()?.uid || this.userDoesNotExist || this.url);
}
return Boolean(this.user) && !this.isNoUser && !this.url && !this.userDoesNotExist;
},
/**
* True if initials should be shown as the user icon fallback
*/
showInitials() {
return !this.noPlaceholder && this.userDoesNotExist && !(this.iconClass || this.$slots.icon);
},
avatarStyle() {
return {
"--avatar-size": this.size + "px",
lineHeight: this.showInitials ? this.size + "px" : 0,
fontSize: Math.round(this.size * 0.45) + "px"
};
},
initialsWrapperStyle() {
const { r, g, b } = usernameToColor(this.userIdentifier);
return {
backgroundColor: `rgba(${r}, ${g}, ${b}, 0.1)`
};
},
initialsStyle() {
const { r, g, b } = usernameToColor(this.userIdentifier);
return {
color: `rgb(${r}, ${g}, ${b})`
};
},
tooltip() {
if (this.disableTooltip) {
return null;
}
if (this.tooltipMessage) {
return this.tooltipMessage;
}
return this.displayName;
},
/**
* Get the (max. two) initials of the user as uppcase string
*/
initials() {
let initials = "?";
if (this.showInitials) {
const user = this.userIdentifier.trim();
if (user === "") {
return initials;
}
const filteredChars = user.match(/[\p{L}\p{N}\s]/gu);
if (!filteredChars) {
return initials;
}
const filtered = filteredChars.join("").trim();
const idx = filtered.lastIndexOf(" ");
initials = String.fromCodePoint(filtered.codePointAt(0));
if (idx !== -1) {
initials = initials.concat(String.fromCodePoint(filtered.codePointAt(idx + 1)));
}
}
return initials.toLocaleUpperCase();
},
/**
* Contacts menu actions for the hover card.
* `null` until actions are loaded so the card can fall back to profile API actions.
*
* @return {Array|null}
*/
hoverCardActions() {
if (this.isLegacy35 || !this.isMenuLoaded) {
return null;
}
return this.menu.length > 0 ? this.menu : null;
},
/**
* Best available display name for the hover card (prop or contacts menu).
*
* @return {string|undefined}
*/
hoverCardDisplayName() {
return this.displayName || this.contactsMenuData?.fullName || void 0;
},
/**
* Status already known by this avatar so the hover card does not fetch it again.
* Omitted while status is still the empty default (fetch in progress).
*
* @return {object|undefined}
*/
hoverCardPreloadedUserStatus() {
if (this.preloadedUserStatus) {
return this.userStatus;
}
if (this.userStatus.status || this.userStatus.icon || this.userStatus.message) {
return this.userStatus;
}
return void 0;
},
menu() {
if (this.isLegacy35) {
return this.legacyMenu;
}
const actions = this.contactsMenuActions.map((item) => {
const route = getRoute(this.$router, item.hyperlink);
return {
id: item.id,
appId: item.appId,
text: item.title,
href: route ? void 0 : item.hyperlink,
to: route || void 0,
icon: item.icon
};
});
for (const action of getEnabledContactsMenuActions(this.contactsMenuData)) {
try {
actions.push({
id: action.id,
text: action.displayName(this.contactsMenuData),
iconSvg: action.iconSvg(this.contactsMenuData),
onClick: () => action.callback(this.contactsMenuData)
});
} catch (error) {
logger.error(`Failed to render ContactsMenu action ${action.id}`, {
error,
action
});
}
}
return actions;
},
/**
* Legacy NcActions menu entries for Nextcloud 32–34.
*
* @return {Array}
*/
legacyMenu() {
const actions = this.contactsMenuActions.map((item) => {
const route = getRoute(this.$router, item.hyperlink);
return {
ncActionComponent: route ? NcActionRouter : NcActionLink,
ncActionComponentProps: route ? {
to: route,
icon: item.icon
} : {
href: item.hyperlink,
icon: item.icon
},
text: item.title
};
});
for (const action of getEnabledContactsMenuActions(this.contactsMenuData)) {
try {
actions.push({
ncActionComponent: NcActionButton,
ncActionComponentProps: {
onClick: () => action.callback(this.contactsMenuData)
},
text: action.displayName(this.contactsMenuData),
iconSvg: action.iconSvg(this.contactsMenuData)
});
} catch (error) {
logger.error(`Failed to render ContactsMenu action ${action.id}`, {
error,
action
});
}
}
function escape(html) {
const text = document.createTextNode(html);
const p = document.createElement("p");
p.appendChild(text);
return p.innerHTML;
}
if (!this.hideStatus && (this.userStatus.icon || this.userStatus.message)) {
const emojiIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<text x="50%" y="50%" text-anchor="middle" style="dominant-baseline: central; font-size: 85%">${escape(this.userStatus.icon)}</text>
</svg>`;
return [{
ncActionComponent: NcActionText,
ncActionComponentProps: {},
iconSvg: this.userStatus.icon ? emojiIcon : void 0,
text: `${this.userStatus.message}`
}].concat(actions);
}
return actions;
}
},
watch: {
url() {
this.userDoesNotExist = false;
this.loadAvatarUrl();
},
user() {
this.userDoesNotExist = false;
this.isMenuLoaded = false;
this.loadAvatarUrl();
},
version: "loadAvatarUrl",
preloadedUserStatus(status) {
if (status) {
this.setUserStatus(status);
}
},
contactsMenuOpenState(shown) {
if (this.isLegacy35) {
return;
}
if (shown) {
this.debouncedFetchContactsMenu();
} else {
this.debouncedFetchContactsMenu.clear();
}
}
},
created() {
this.debouncedFetchContactsMenu = debounce(this.fetchContactsMenu, 300);
},
mounted() {
this.loadAvatarUrl();
subscribe("settings:avatar:updated", this.loadAvatarUrl);
subscribe("settings:display-name:updated", this.loadAvatarUrl);
if (!this.hideStatus && this.user && !this.isNoUser) {
if (!this.preloadedUserStatus) {
this.fetchUserStatus(this.user);
} else {
this.setUserStatus(this.preloadedUserStatus);
}
subscribe("user_status:status.updated", this.handleUserStatusUpdated);
} else if (!this.hideStatus && this.preloadedUserStatus) {
this.setUserStatus(this.preloadedUserStatus);
}
},
beforeUnmount() {
this.debouncedFetchContactsMenu.clear();
unsubscribe("settings:avatar:updated", this.loadAvatarUrl);
unsubscribe("settings:display-name:updated", this.loadAvatarUrl);
unsubscribe("user_status:status.updated", this.handleUserStatusUpdated);
},
methods: {
t,
handleUserStatusUpdated(state) {
if (this.user === state.userId) {
this.userStatus = {
status: state.status,
icon: state.icon,
message: state.message
};
this.hasStatus = state.status !== null;
}
},
/**
* Toggle the legacy popover menu on click or enter
*
* @param {KeyboardEvent|MouseEvent} event the UI event
*/
async toggleMenu(event) {
if (event.type === "keydown" && event.key !== "Enter") {
return;
}
if (!this.contactsMenuOpenState) {
await this.fetchContactsMenu();
}
this.contactsMenuOpenState = !this.contactsMenuOpenState;
},
closeMenu() {
if (!this.isLegacy35) {
return;
}
this.contactsMenuOpenState = false;
},
async fetchContactsMenu() {
this.contactsMenuLoading = true;
try {
const user = encodeURIComponent(this.user);
const { data } = await axios.post(generateUrl("contactsmenu/findOne"), `shareType=0&shareWith=${user}`);
this.contactsMenuData = data;
this.contactsMenuActions = data.topAction ? [data.topAction].concat(data.actions) : data.actions;
} catch {
this.contactsMenuData = {};
this.contactsMenuActions = [];
if (this.isLegacy35) {
this.contactsMenuOpenState = false;
}
}
this.contactsMenuLoading = false;
this.isMenuLoaded = true;
},
/**
* Handle avatar loading if user or url defined
*/
loadAvatarUrl() {
this.isAvatarLoaded = false;
if (!this.isUrlDefined && (!this.isUserDefined || this.isNoUser || this.iconClass || this.$slots.icon)) {
this.isAvatarLoaded = true;
this.userDoesNotExist = true;
return;
}
if (this.isUrlDefined) {
this.updateImageIfValid(this.url);
return;
}
if (this.size <= 64) {
const avatarUrl = this.avatarUrlGenerator(this.user, 64);
const srcset = [
`${avatarUrl} ${density(64 * SMALL_VARIANT_UPSCALE / this.size)}x`,
`${this.avatarUrlGenerator(this.user, 512)} ${density(512 / this.size)}x`
].join(", ");
this.updateImageIfValid(avatarUrl, srcset);
} else {
const avatarUrl = this.avatarUrlGenerator(this.user, 512);
this.updateImageIfValid(avatarUrl);
}
},
/**
* Generate an avatar url from the server's avatar endpoint
*
* @param {string} user the user id
* @param {number} size the desired size
* @return {string}
*/
avatarUrlGenerator(user, size) {
const version = this.version ?? (user === getCurrentUser()?.uid ? window.oc_userconfig?.avatar?.version : void 0);
return getAvatarUrl(user, {
size,
isDarkTheme: this.isDarkTheme,
isGuest: this.isGuest,
version
});
},
/**
* Check if the provided url is valid and update Avatar if so
*
* @param {string} url the avatar url
* @param {Array} srcset the avatar srcset
*/
updateImageIfValid(url, srcset = null) {
const userHasAvatar = getUserHasAvatar(this.user);
if (this.isUserDefined && typeof userHasAvatar === "boolean") {
this.isAvatarLoaded = true;
this.avatarUrlLoaded = url;
if (srcset) {
this.avatarSrcSetLoaded = srcset;
}
if (userHasAvatar === false) {
this.userDoesNotExist = true;
}
return;
}
const img = new Image();
img.onload = () => {
this.avatarUrlLoaded = url;
if (srcset) {
this.avatarSrcSetLoaded = srcset;
}
this.isAvatarLoaded = true;
setUserHasAvatar(this.user, true);
};
img.onerror = (error) => {
logger.debug("[NcAvatar] Invalid avatar url", { error, url });
this.avatarUrlLoaded = null;
this.avatarSrcSetLoaded = null;
this.userDoesNotExist = true;
this.isAvatarLoaded = false;
setUserHasAvatar(this.user, false);
};
if (srcset) {
img.srcset = srcset;
}
img.src = url;
}
}
};
const _hoisted_1 = ["title"];
const _hoisted_2 = ["src", "srcset"];
const _hoisted_3 = ["aria-label"];
const _hoisted_4 = {
key: 2,
class: "avatardiv__user-status avatardiv__user-status--icon"
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_NcLoadingIcon = resolveComponent("NcLoadingIcon");
const _component_IconDotsHorizontal = resolveComponent("IconDotsHorizontal");
const _component_NcButton = resolveComponent("NcButton");
const _component_NcIconSvgWrapper = resolveComponent("NcIconSvgWrapper");
const _component_NcActions = resolveComponent("NcActions");
const _component_NcProfileHoverCard = resolveComponent("NcProfileHoverCard");
const _component_NcPopover = resolveComponent("NcPopover");
const _component_NcUserStatusIcon = resolveComponent("NcUserStatusIcon");
const _directive_click_outside = resolveDirective("click-outside");
return withDirectives((openBlock(), createElementBlock("span", {
class: normalizeClass(["avatardiv popovermenu-wrapper", {
"avatardiv--unknown": $data.userDoesNotExist,
"avatardiv--with-menu": $options.hasMenu,
"avatardiv--with-legacy-menu": $options.hasMenu && $setup.isLegacy35,
"avatardiv--with-menu-loading": $data.contactsMenuLoading
}]),
style: normalizeStyle($options.avatarStyle),
title: $options.tooltip
}, [
renderSlot(_ctx.$slots, "icon", {}, () => [
$props.iconClass ? (openBlock(), createElementBlock("span", {
key: 0,
class: normalizeClass([$props.iconClass, "avatar-class-icon"])
}, null, 2)) : $data.isAvatarLoaded && !$data.userDoesNotExist ? (openBlock(), createElementBlock("img", {
key: 1,
src: $data.avatarUrlLoaded,
srcset: $data.avatarSrcSetLoaded,
alt: ""
}, null, 8, _hoisted_2)) : createCommentVNode("", true)
], true),
$setup.isLegacy35 && $options.hasMenu ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
$options.menu.length === 0 ? (openBlock(), createBlock(_component_NcButton, {
key: 0,
"aria-label": $options.avatarAriaLabel,
class: "action-item action-item__menutoggle",
variant: "tertiary-no-background",
onClick: $options.toggleMenu
}, {
icon: withCtx(() => [
$data.contactsMenuLoading ? (openBlock(), createBlock(_component_NcLoadingIcon, { key: 0 })) : (openBlock(), createBlock(_component_IconDotsHorizontal, {
key: 1,
size: 20
}))
]),
_: 1
}, 8, ["aria-label", "onClick"])) : (openBlock(), createBlock(_component_NcActions, {
key: 1,
open: $data.contactsMenuOpenState,
"onUpdate:open": _cache[0] || (_cache[0] = ($event) => $data.contactsMenuOpenState = $event),
"aria-label": $options.avatarAriaLabel,
container: $props.menuContainer,
forceMenu: "",
manualOpen: "",
variant: "tertiary-no-background",
onClick: $options.toggleMenu
}, createSlots({
default: withCtx(() => [
(openBlock(true), createElementBlock(Fragment, null, renderList($options.menu, (item, key) => {
return openBlock(), createBlock(resolveDynamicComponent(item.ncActionComponent), mergeProps({ key }, { ref_for: true }, item.ncActionComponentProps), createSlots({
default: withCtx(() => [
createTextVNode(" " + toDisplayString(item.text), 1)
]),
_: 2
}, [
item.iconSvg ? {
name: "icon",
fn: withCtx(() => [
createVNode(_component_NcIconSvgWrapper, {
svg: item.iconSvg
}, null, 8, ["svg"])
]),
key: "0"
} : void 0
]), 1040);
}), 128))
]),
_: 2
}, [
$data.contactsMenuLoading ? {
name: "icon",
fn: withCtx(() => [
createVNode(_component_NcLoadingIcon)
]),
key: "0"
} : void 0
]), 1032, ["open", "aria-label", "container", "onClick"]))
], 64)) : $options.hasMenu ? (openBlock(), createBlock(_component_NcPopover, {
key: 1,
shown: $data.contactsMenuOpenState,
"onUpdate:shown": _cache[1] || (_cache[1] = ($event) => $data.contactsMenuOpenState = $event),
class: "avatar-profile-popover",
container: $props.menuContainer,
delay: { show: 400, hide: 0 },
popoverTriggers: ["hover"],
triggers: ["hover", "focus", "click"],
noFocusTrap: "",
popupRole: "dialog"
}, {
trigger: withCtx(({ attrs }) => [
createElementVNode("span", mergeProps({ class: "avatar-profile-popover__trigger" }, attrs, {
role: "button",
tabindex: "0",
"aria-label": $options.avatarAriaLabel
}), null, 16, _hoisted_3)
]),
default: withCtx(() => [
createVNode(_component_NcProfileHoverCard, {
user: $props.user,
displayName: $options.hoverCardDisplayName,
open: $data.contactsMenuOpenState,
actions: $options.hoverCardActions,
actionsLoading: $data.contactsMenuLoading,
preloadedUserStatus: $options.hoverCardPreloadedUserStatus
}, null, 8, ["user", "displayName", "open", "actions", "actionsLoading", "preloadedUserStatus"])
]),
_: 1
}, 8, ["shown", "container"])) : createCommentVNode("", true),
$options.showUserStatusIconOnAvatar ? (openBlock(), createElementBlock("span", _hoisted_4, toDisplayString(_ctx.userStatus.icon), 1)) : $options.canDisplayUserStatus ? (openBlock(), createBlock(_component_NcUserStatusIcon, {
key: 3,
class: "avatardiv__user-status",
status: _ctx.userStatus.status,
"aria-hidden": String($options.hasMenu)
}, null, 8, ["status", "aria-hidden"])) : createCommentVNode("", true),
$options.showInitials ? (openBlock(), createElementBlock("span", {
key: 4,
style: normalizeStyle($options.initialsWrapperStyle),
class: "avatardiv__initials-wrapper"
}, [
createElementVNode("span", {
style: normalizeStyle($options.initialsStyle),
class: "avatardiv__initials"
}, toDisplayString($options.initials), 5)
], 4)) : createCommentVNode("", true)
], 14, _hoisted_1)), [
[_directive_click_outside, $options.closeMenu]
]);
}
const NcAvatar = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-b005f1da"]]);
export {
NcAvatar as N,
userStatus as u
};
//# sourceMappingURL=NcAvatar.mjs.map