Newer
Older
gnexus-ui-kit / src / vue / components / GnUserCard.js
import { defineComponent, h } from "vue";
import { cx, iconNode } from "../utils.js";
import GnAvatar from "./GnAvatar.js";

export default defineComponent({
	name: "GnUserCard",
	props: {
		name: { type: String, required: true },
		email: { type: String, default: "" },
		role: { type: String, default: "" },
		avatar: { type: Object, default: () => ({}) },
		href: { type: String, default: "" },
		compact: { type: Boolean, default: false },
		actions: { type: Array, default: () => [] }
	},
	setup(props, { slots }) {
		const renderAvatar = () => slots.avatar?.() || h(GnAvatar, {
			...props.avatar,
			size: props.compact ? "sm" : "md"
		});

		const renderIdentity = () => h("span", { class: "identity" }, [
			renderAvatar(),
			h("span", { class: "identity-content" }, [
				h("span", { class: "identity-title" }, props.name),
				props.email && h("span", { class: "identity-meta" }, props.email)
			])
		]);

		const renderActions = () => {
			if (slots.actions) return slots.actions();
			if (!props.actions.length) return null;

			return h("div", { class: "user-card-actions" },
				props.actions.map(action => {
					if (props.compact) {
						return h("button", {
							class: "btn-icon",
							type: "button",
							"aria-label": action.label,
							onClick: action.onClick
						}, [iconNode(action.icon)]);
					}

					const hasIcon = !!action.icon;
					const btnClass = cx("btn", "btn-small", {
						[`btn-${action.variant}`]: action.variant,
						"btn-secondary": !action.variant,
						"with-icon": hasIcon
					});

					return h("button", {
						class: btnClass,
						type: "button",
						onClick: action.onClick
					}, [
						hasIcon && iconNode(action.icon),
						action.label
					]);
				})
			);
		};

		return () => {
			const rootClass = cx("card", "user-card", { "user-card-compact": props.compact });
			const bodyChildren = [];

			if (props.href) {
				bodyChildren.push(
					h("a", {
						class: "profile-identity",
						href: props.href,
						target: "_blank",
						rel: "noopener noreferrer"
					}, [renderIdentity()])
				);
			} else {
				bodyChildren.push(renderIdentity());
			}

			if (!props.compact && props.role) {
				bodyChildren.push(h("span", { class: "user-card-role" }, props.role));
			}

			if (slots.default && !props.compact) {
				bodyChildren.push(h("div", { class: "user-card-extra" }, slots.default()));
			}

			const actionsNode = renderActions();
			if (actionsNode) {
				bodyChildren.push(actionsNode);
			}

			return h("article", { class: rootClass }, [
				h("div", { class: "user-card-body" }, bodyChildren)
			]);
		};
	}
});