Skip to content

Commit fcd0204

Browse files
committed
feat(avatar): update to new visual language
1 parent 6615cfc commit fcd0204

File tree

8 files changed

+166
-18
lines changed

8 files changed

+166
-18
lines changed

.changeset/moody-banks-study.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"@stackoverflow/stacks": patch
3+
"@stackoverflow/stacks-svelte": patch
4+
---
5+
6+
**Avatar Updates:**
7+
8+
- **Stacks Classic**: Made avatar border squared. Introduced `.s-avatar--indicator` class for positioning an activity indicator element in relation to the avatar.
9+
10+
- **Stacks Svelte**: Introduced a new `status` prop. When set to `online` it will show an activity indicator on the avatar.

packages/stacks-classic/lib/components/avatar/avatar.less

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
.s-avatar {
22
--_av-size: var(--su-static16);
33
--_av-bg: var(--_white-static); // Force a white background color for when we have transparent avatars
4-
--_av-br: var(--br-sm);
54
--_av-fs-letter: calc(var(--su-static12) - var(--su-static1));
65
--_av-scale-badge: 1;
76

@@ -18,14 +17,8 @@
1817

1918
// MODIFIERS
2019
// Sizes
21-
&&__32,
22-
&&__48 {
23-
--_av-br: var(--br-md);
24-
}
25-
2620
&&__96,
2721
&&__128 {
28-
--_av-br: calc(var(--br-lg) + var(--br-sm));
2922
--_av-scale-badge: 3;
3023
}
3124

@@ -49,7 +42,6 @@
4942

5043
&&__64 {
5144
--_av-size: var(--su-static64);
52-
--_av-br: var(--br-lg);
5345
--_av-fs-letter: calc(var(--su-static48) - var(--su-static4));
5446
--_av-scale-badge: 2.4;
5547
}
@@ -74,7 +66,6 @@
7466
}
7567

7668
& &--image {
77-
border-radius: var(--_av-br);
7869
display: block;
7970
height: var(--_av-size);
8071
width: var(--_av-size);
@@ -95,8 +86,15 @@
9586
user-select: none;
9687
}
9788

98-
background-color: var(--_av-bg);
99-
border-radius: var(--_av-br);
89+
& &--indicator {
90+
box-shadow: 0 0 0 var(--su-static2) var(--white);
91+
bottom: 100%;
92+
left: 100%;
93+
position: absolute;
94+
transform: translate(-50%, 80%);
95+
}
96+
97+
background-color: var(--_av-bg);
10098
height: var(--_av-size);
10199
width: var(--_av-size);
102100

packages/stacks-docs/_data/avatars-component.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
"applies": "N/A",
2121
"description": "A child element that provides positioning to the shield on Team avatars."
2222
},
23+
{
24+
"class": ".s-avatar--indicator",
25+
"applies": "N/A",
26+
"description": "A child element that provides positioning to the activity indicator on user's avatars."
27+
},
2328
{
2429
"class": ".s-avatar__24",
2530
"applies": ".s-avatar",

packages/stacks-docs/_data/site-navigation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@
204204
},
205205
{
206206
"title": "Avatars",
207-
"url": "/product/components/avatars/"
207+
"url": "/product/components/avatars/",
208+
"new": true
208209
},
209210
{
210211
"title": "Award bling",

packages/stacks-docs/product/components/avatars.html

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
layout: page
33
title: Avatars
44
svelte: https://beta.svelte.stackoverflow.design/?path=/docs/components-avatar--docs
5-
figma: https://svelte.stackoverflow.design/figma/avatars
5+
figma: https://www.figma.com/design/do4Ug0Yws8xCfRjHe9cJfZ/Project-SHINE---Product-UI?node-id=610-18797&p=f&t=c9NSyJWdASb80eVC-0
66
description: Avatars are used to quickly identify users or teams.
77
tags: components
88
---
@@ -32,7 +32,7 @@
3232
<section class="stacks-section">
3333
{% header "h2", "Examples" %}
3434
{% header "h3", "Users" %}
35-
<p class="stacks-copy">Including an image with the class <code class="stacks-code">s-avatar--image</code> within <code class="stacks-code">s-avatar</code> will apply the correct size and border radius. Remember, you’ll want to double the size of the avatar image to account for retina screens.</p>
35+
<p class="stacks-copy">Including an image with the class <code class="stacks-code">s-avatar--image</code> within <code class="stacks-code">s-avatar</code> will apply the correct size. Remember, you’ll want to double the size of the avatar image to account for retina screens.</p>
3636
<div class="stacks-preview">
3737
{% highlight html %}
3838
<a href="" class="s-avatar">
@@ -146,11 +146,66 @@
146146
</table>
147147
</div>
148148
</div>
149+
150+
{% header "h3", "Activity" %}
151+
<p class="stacks-copy">
152+
Avatars can display <a href="/product/components/activity-indicator/">activity indicators</a> to show activities or status changes.
153+
Add the <code class="stacks-code">s-avatar--indicator</code> class to a child element of <code class="stacks-code">s-avatar</code> along with <code class="stacks-code">s-activity-indicator</code> and <code class="stacks-code">s-activity-indicator__sm</code> classes.
154+
The indicator is positioned at the top-right corner of the avatar.</p>
155+
<div class="stacks-preview">
156+
{% highlight html %}
157+
<a href="" class="s-avatar">
158+
<div class="s-avatar--indicator s-activity-indicator s-activity-indicator__sm s-activity-indicator__success">
159+
<div class="v-visible-sr">Online</div>
160+
</div>
161+
<img class="s-avatar--image" src="https://picsum.photos/32" />
162+
</a>
163+
164+
<a href="" class="s-avatar s-avatar__24">
165+
<div class="s-avatar--indicator s-activity-indicator s-activity-indicator__success">
166+
<div class="v-visible-sr">Online</div>
167+
</div>
168+
<img class="s-avatar--image" src="https://picsum.photos/48" />
169+
</a>
170+
{% endhighlight %}
171+
<div class="stacks-preview--example overflow-x-auto">
172+
<table class="s-table s-table__b0 s-table__sm">
173+
<tr>
174+
<td class="ws2">
175+
<code class="stacks-code">16px</code>
176+
<code class="stacks-code">default</code>
177+
</td>
178+
<td>
179+
<a href="#" class="s-avatar">
180+
<div class="s-avatar--indicator s-activity-indicator s-activity-indicator__sm s-activity-indicator__success">
181+
<div class="v-visible-sr">Online</div>
182+
</div>
183+
<img class="s-avatar--image" alt="demo avatar" src="https://picsum.photos/32" />
184+
</a>
185+
</td>
186+
</tr>
187+
<tr>
188+
<td class="ws2">
189+
<code class="stacks-code">24px</code>
190+
<code class="stacks-code">.s-avatar__24</code>
191+
</td>
192+
<td>
193+
<a href="#" class="s-avatar s-avatar__24">
194+
<div class="s-avatar--indicator s-activity-indicator s-activity-indicator__success">
195+
<div class="v-visible-sr">Online</div>
196+
</div>
197+
<img class="s-avatar--image" alt="demo avatar" src="https://picsum.photos/48" />
198+
</a>
199+
</td>
200+
</tr>
201+
</table>
202+
</div>
203+
</div>
149204
</section>
150205

151206
<section class="stacks-section">
152-
{% header "h3", "Teams" %}
153-
<p class="stacks-copy">When displaying a team’s identity, we badge the avatar with a shield. We fall back to the first letter of their name and a color we choose at random. As team administrators add more data—choosing a color or uploading an avatar—we progressively enhance the avatar.</p>
207+
{% header "h3", "Stack Internal" %}
208+
<p class="stacks-copy">When displaying a team’s identity, we badge the avatar with a shield. We fall back to the first letter of their name and a color we choose at random. As Stack Internal administrators add more data—choosing a color or uploading an avatar—we progressively enhance the avatar.</p>
154209
<p class="stacks-copy">In this example, from left to right, we have a team name of Hum with no avatar or custom color. In the middle we have a team name of Hum with a custom color. In the last example, we have a team name of Hum with a custom avatar applied.</p>
155210
<div class="stacks-preview">
156211
{% highlight html %}

packages/stacks-svelte/src/components/Avatar/Avatar.stories.svelte

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
</Story>
5656

5757
<Story
58-
name="href"
58+
name="As a link"
5959
args={{
6060
name: "href example",
6161
href: "#",
@@ -75,11 +75,48 @@
7575
/>
7676

7777
<Story
78-
name="badge"
78+
name="Badge"
7979
args={{
8080
name: "badge example",
8181
badge: true,
8282
src: "https://picsum.photos/64",
8383
size: 64,
8484
}}
8585
/>
86+
87+
<Story name="Status" asChild>
88+
<div class="d-flex fd-column g64">
89+
<table class="s-table s-table__bx-simple wmx7">
90+
<thead>
91+
<tr>
92+
<th scope="col">Sizes</th>
93+
<th scope="col" class="s-table--cell8">Example</th>
94+
</tr>
95+
</thead>
96+
97+
<tbody>
98+
<tr>
99+
<th scope="row" class="va-middle">16</th>
100+
<td class="va-middle px4">
101+
<Avatar
102+
name="username"
103+
src="https://picsum.photos/32"
104+
status="online"
105+
/>
106+
</td>
107+
</tr>
108+
<tr>
109+
<th scope="row" class="va-middle">24</th>
110+
<td class="va-middle px4">
111+
<Avatar
112+
name="username"
113+
src="https://picsum.photos/48"
114+
status="online"
115+
size={24}
116+
/>
117+
</td>
118+
</tr>
119+
</tbody>
120+
</table>
121+
</div>
122+
</Story>

packages/stacks-svelte/src/components/Avatar/Avatar.svelte

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
<script lang="ts">
66
import Icon from "../Icon/Icon.svelte";
7+
import ActivityIndicator from "../ActivityIndicator/ActivityIndicator.svelte";
78
import { IconShieldXSm } from "@stackoverflow/stacks-icons-legacy/icons";
89
import type { HTMLAnchorAttributes } from "svelte/elements";
910
@@ -33,6 +34,11 @@
3334
*/
3435
letter?: string;
3536
37+
/**
38+
* User status
39+
*/
40+
status?: "online";
41+
3642
/**
3743
* Boolean to show the shield badge on the avatar
3844
*/
@@ -50,6 +56,7 @@
5056
href,
5157
src,
5258
letter,
59+
status,
5360
badge = false,
5461
class: className = "",
5562
role,
@@ -87,6 +94,14 @@
8794
<span class="s-avatar--letter" aria-hidden="true">{letter}</span>
8895
{/if}
8996
<span class="v-visible-sr">{name}</span>
97+
{#if status === "online"}
98+
<ActivityIndicator
99+
label="Online"
100+
variant="success"
101+
size={size === 16 ? "sm" : ""}
102+
class="s-avatar--indicator"
103+
/>
104+
{/if}
90105
{#if badge}
91106
<!-- TODO This badge is not purely decorative, so it should include descriptive text
92107
(see https://stackoverflow.atlassian.net/browse/A11Y-126) -->

packages/stacks-svelte/src/components/Avatar/Avatar.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,33 @@ describe("Avatar", () => {
5757
expect(badgeElement).to.exist;
5858
});
5959

60+
it("should render the online status small indicator when status is online and size is 16", () => {
61+
render(Avatar, {
62+
name: "test avatar",
63+
status: "online",
64+
});
65+
const smallIndicatorEl = screen
66+
.getByText("test avatar")
67+
.parentElement?.querySelector(".s-avatar--indicator");
68+
expect(smallIndicatorEl).to.exist;
69+
expect(smallIndicatorEl).to.have.class("s-activity-indicator__sm");
70+
expect(screen.getByText("Online")).to.exist;
71+
});
72+
73+
it("should render the online status large indicator when status is online and size is above 16", () => {
74+
render(Avatar, {
75+
name: "test avatar",
76+
status: "online",
77+
size: 24,
78+
});
79+
const largeIndicatorEl = screen
80+
.getByText("test avatar")
81+
.parentElement?.querySelector(".s-avatar--indicator");
82+
expect(largeIndicatorEl).to.exist;
83+
expect(largeIndicatorEl).not.to.have.class("s-activity-indicator__sm");
84+
expect(screen.getByText("Online")).to.exist;
85+
});
86+
6087
it("should render the avatar with artbirary classes", () => {
6188
render(Avatar, {
6289
name: "test avatar",

0 commit comments

Comments
 (0)