Files
WRNexusJS/packages/ui/components/avatar.wrn
T

352 lines
9.4 KiB
Plaintext

component Avatar {
outputs {
load(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
error(payload: { error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string)
click(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object })
}
props {
src: string = ""
alt: string = ""
initials: string = ""
size: string = "md"
color: string = "primary"
variant: string = "solid"
shape: string = "circle"
status: string = ""
statusLabel: string = ""
statusPosition: string = "bottom"
badge: string = ""
badgeIcon: string = ""
badgeLabel: string = ""
tooltip: string = ""
name: string = ""
description: string = ""
loading: string = "lazy"
class: string = ""
}
view {
<span
{...attrs}
class="wire-next wire-next--avatar {description ? 'wire-next--avatar-media' : ''} {class}"
data-wrn-avatar
>
<span
class="wire-next__avatar-wrap"
data-shape="{shape}"
data-size="{size}"
data-color="{color}"
data-variant="{variant}"
data-status-position="{statusPosition}"
tabindex="{tooltip ? '0' : '-1'}"
aria-label="{tooltip || name || alt || initials || 'Avatar'}"
>
<span class="wire-next__avatar">
{#if src}
<img src="{src}" alt="{alt || name}" loading="{loading}" />
{:else if initials}
<span class="wire-next__avatar-initials" aria-hidden="true">{initials}</span>
{:else}
<span class="wire-next__avatar-placeholder icon-[lucide--user-round]" aria-hidden="true"></span>
{/if}
</span>
{#if status}
<span
class="wire-next__avatar-status"
data-status="{status}"
title="{statusLabel || status}"
aria-label="{statusLabel || status}"
></span>
{/if}
{#if badgeIcon}
<span class="wire-next__avatar-badge" aria-label="{badgeLabel || 'Linked account'}">
<span class="{badgeIcon}" aria-hidden="true"></span>
</span>
{:else if badge}
<span class="wire-next__avatar-badge wire-next__avatar-badge--text" aria-label="{badgeLabel || badge}">
{badge}
</span>
{/if}
{#if tooltip}
<span class="wire-next__avatar-tooltip" role="tooltip">{tooltip}</span>
{/if}
</span>
{#if description}
<span class="wire-next__avatar-copy">
<strong>{name || alt || initials}</strong>
<span>{description}</span>
</span>
{/if}
</span>
}
style {
/* --- Avatar -------------------------------------------------------------- */
.wire-next--avatar {
display: inline-flex;
width: fit-content;
max-width: 100%;
align-items: center;
}
.wire-next--avatar-media {
gap: 0.8rem;
}
.wire-next__avatar-wrap {
--wire-avatar-size: 3rem;
--wire-avatar-color: var(--wire-color-primary);
position: relative;
display: inline-grid;
width: var(--wire-avatar-size);
height: var(--wire-avatar-size);
flex: none;
place-items: center;
border-radius: 999px;
outline: none;
}
.wire-next__avatar-wrap[data-size="xs"] {
--wire-avatar-size: 1.75rem;
}
.wire-next__avatar-wrap[data-size="sm"] {
--wire-avatar-size: 2.25rem;
}
.wire-next__avatar-wrap[data-size="md"],
.wire-next__avatar-wrap[data-size="default"] {
--wire-avatar-size: 3rem;
}
.wire-next__avatar-wrap[data-size="lg"] {
--wire-avatar-size: 4rem;
}
.wire-next__avatar-wrap[data-size="xl"] {
--wire-avatar-size: 5rem;
}
.wire-next__avatar-wrap[data-color="secondary"] {
--wire-avatar-color: #737373;
}
.wire-next__avatar-wrap[data-color="success"] {
--wire-avatar-color: var(--wire-color-success);
}
.wire-next__avatar-wrap[data-color="info"] {
--wire-avatar-color: var(--wire-color-info);
}
.wire-next__avatar-wrap[data-color="danger"] {
--wire-avatar-color: var(--wire-color-danger);
}
.wire-next__avatar-wrap[data-color="warning"] {
--wire-avatar-color: var(--wire-color-warning);
}
.wire-next__avatar-wrap[data-color="light"] {
--wire-avatar-color: #f4f4f5;
}
.wire-next__avatar-wrap[data-color="dark"] {
--wire-avatar-color: #27272a;
}
.wire-next__avatar {
display: grid;
width: 100%;
height: 100%;
overflow: hidden;
place-items: center;
color: white;
border: 1px solid color-mix(in srgb, var(--wire-avatar-color) 58%, var(--wire-color-border));
border-radius: inherit;
background: var(--wire-avatar-color);
box-shadow:
0 0 0 2px var(--wire-color-bg),
0 5px 14px rgb(0 0 0 / 0.16);
}
.wire-next__avatar-wrap[data-shape="rounded"] {
border-radius: calc(var(--wire-radius-sm, 0.5rem) * 0.72);
}
.wire-next__avatar-wrap[data-shape="square"] {
border-radius: 0;
}
.wire-next__avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.wire-next__avatar-initials {
font-size: calc(var(--wire-avatar-size) * 0.32);
font-weight: 750;
line-height: 1;
letter-spacing: -0.02em;
}
.wire-next__avatar-placeholder {
width: 54%;
height: 54%;
color: currentColor;
opacity: 0.72;
}
.wire-next__avatar-wrap[data-variant="soft"] .wire-next__avatar {
color: var(--wire-avatar-color);
border-color: transparent;
background: color-mix(in srgb, var(--wire-avatar-color) 15%, var(--wire-color-surface));
box-shadow: none;
}
.wire-next__avatar-wrap[data-variant="outline"] .wire-next__avatar {
color: var(--wire-avatar-color);
border-color: var(--wire-avatar-color);
background: transparent;
box-shadow: none;
}
.wire-next__avatar-wrap[data-variant="white"] .wire-next__avatar {
color: var(--wire-color-text);
border-color: var(--wire-color-border);
background: var(--wire-color-surface);
box-shadow: 0 4px 12px rgb(0 0 0 / 0.12);
}
.wire-next__avatar-status {
position: absolute;
right: -0.04rem;
bottom: -0.04rem;
z-index: 2;
width: max(0.58rem, calc(var(--wire-avatar-size) * 0.24));
height: max(0.58rem, calc(var(--wire-avatar-size) * 0.24));
border: 2px solid var(--wire-color-bg);
border-radius: 999px;
background: var(--wire-color-muted);
}
.wire-next__avatar-wrap[data-status-position="top"] .wire-next__avatar-status {
top: -0.04rem;
bottom: auto;
}
.wire-next__avatar-status[data-status="online"],
.wire-next__avatar-status[data-status="success"] {
background: #14cba8;
}
.wire-next__avatar-status[data-status="busy"],
.wire-next__avatar-status[data-status="danger"] {
background: #fb5b68;
}
.wire-next__avatar-status[data-status="away"],
.wire-next__avatar-status[data-status="warning"] {
background: #ffc400;
}
.wire-next__avatar-badge {
position: absolute;
right: -0.25rem;
bottom: -0.25rem;
z-index: 3;
display: grid;
width: max(1rem, calc(var(--wire-avatar-size) * 0.42));
height: max(1rem, calc(var(--wire-avatar-size) * 0.42));
place-items: center;
color: white;
border: 2px solid var(--wire-color-bg);
border-radius: 999px;
background: #27272a;
box-shadow: 0 4px 10px rgb(0 0 0 / 0.22);
}
.wire-next__avatar-badge > span {
width: 62%;
height: 62%;
}
.wire-next__avatar-badge--text {
font-size: calc(var(--wire-avatar-size) * 0.18);
font-weight: 800;
}
.wire-next__avatar-tooltip {
position: absolute;
left: 50%;
bottom: calc(100% + 0.65rem);
z-index: 20;
width: max-content;
max-width: 15rem;
padding: 0.4rem 0.6rem;
color: var(--wire-color-bg);
border-radius: 0.4rem;
background: var(--wire-color-text);
box-shadow: 0 8px 22px rgb(0 0 0 / 0.2);
font-size: 0.75rem;
font-weight: 650;
line-height: 1.25;
pointer-events: none;
opacity: 0;
transform: translate(-50%, 0.25rem);
transition:
opacity var(--wire-motion-fast) var(--wire-ease-standard),
transform var(--wire-motion-fast) var(--wire-ease-standard);
}
.wire-next__avatar-tooltip::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
border: 0.3rem solid transparent;
border-top-color: var(--wire-color-text);
transform: translateX(-50%);
}
.wire-next__avatar-wrap:hover .wire-next__avatar-tooltip,
.wire-next__avatar-wrap:focus-visible .wire-next__avatar-tooltip {
opacity: 1;
transform: translate(-50%, 0);
}
.wire-next__avatar-wrap:focus-visible {
outline: 2px solid var(--wire-avatar-color);
outline-offset: 4px;
}
.wire-next__avatar-copy {
display: grid;
min-width: 0;
gap: 0.15rem;
}
.wire-next__avatar-copy strong {
color: var(--wire-color-text);
font-size: 0.9rem;
}
.wire-next__avatar-copy > span {
overflow: hidden;
color: var(--wire-color-muted);
font-size: 0.78rem;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}