Skip to content

Commit

Permalink
Feat(web): Introduce UNSTABLE_Avatar component #DS-1323
Browse files Browse the repository at this point in the history
  • Loading branch information
crishpeen authored and pavelklibani committed Jun 21, 2024
1 parent d35239a commit b9e0254
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 1 deletion.
101 changes: 101 additions & 0 deletions packages/web/src/scss/components/UNSTABLE_Avatar/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# UNSTABLE Avatar

⚠️ This component is UNSTABLE. It may significantly change at any point in the future.
Please use it with caution.

The `UNSTABLE_Avatar` component is used to represent a user or entity.

It can be a circle or a square (with rounded corners, using `radius-100` token) and
can have different sizes.

## Example

```html
<div class="UNSTABLE_Avatar UNSTABLE_Avatar--medium" aria-label="Profile of Jiří Bárta">
<span aria-hidden="true">JB</span>
</div>

<a href="#" class="UNSTABLE_Avatar UNSTABLE_Avatar--xsmall" aria-label="Profile of Jiří Bárta">
<img src="https://picsum.photos/id/823/162/162" alt="Jiří Bárta" aria-hidden="true" />
</a>
```

## Square

Add `UNSTABLE_Avatar--square` modifier to make the avatar a square.

```html
<div class="UNSTABLE_Avatar UNSTABLE_Avatar--medium UNSTABLE_Avatar--square" aria-label="Profile of Jiří Bárta">
<span aria-hidden="true">JB</span>
</div>
```

## Sizes

The Avatar component supports `xsmall`, `small`, `medium`, `large`, and `xlarge` sizes.

```html
<div class="UNSTABLE_Avatar UNSTABLE_Avatar--xsmall" aria-label="Profile of Jiří Bárta">
<span aria-hidden="true">JB</span>
</div>
<div class="UNSTABLE_Avatar UNSTABLE_Avatar--small" aria-label="Profile of Jiří Bárta">
<span aria-hidden="true">JB</span>
</div>
<div class="UNSTABLE_Avatar UNSTABLE_Avatar--medium" aria-label="Profile of Jiří Bárta">
<span aria-hidden="true">JB</span>
</div>
<div class="UNSTABLE_Avatar UNSTABLE_Avatar--large" aria-label="Profile of Jiří Bárta">
<span aria-hidden="true">JB</span>
</div>
<div class="UNSTABLE_Avatar UNSTABLE_Avatar--xlarge" aria-label="Profile of Jiří Bárta">
<span aria-hidden="true">JB</span>
</div>
```

## Content

The content of the `UNSTABLE_Avatar` component can be an image, an icon, or a text string.

### Icon

Add an icon with correct size.

```html
<div class="UNSTABLE_Avatar UNSTABLE_Avatar--medium" aria-label="Profile of Jiří Bárta">
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/assets/icons/svg/sprite.svg#profile" />
</svg>
</div>
```

ℹ️ Don't forget to add the `aria-label` attribute for accessible title.

### Image

Add an image, it will be resized to fit the avatar.

```html
<div class="UNSTABLE_Avatar UNSTABLE_Avatar--medium" aria-label="Profile of Jiří Bárta">
<img src="https://picsum.photos/id/823/162/162" alt="Jiří Bárta" aria-hidden="true" />
</div>
```

ℹ️ Don't forget to add the `aria-label` attribute for accessible title.
The image should have an `alt` attribute set and can be aria-hidden, because the `aria-label`
attribute is set on the container.

### Text

It is possible to use text as the content of the `UNSTABLE_Avatar` component.
This is useful when you want to display the initials of a user. You need to
take care of the text length and case. The rest is handled by the component.

```html
<div class="UNSTABLE_Avatar UNSTABLE_Avatar--medium" aria-label="Profile of Jiří Bárta">
<span aria-hidden="true">JB</span>
</div>
```

ℹ️ Don't forget to add the `aria-label` attribute for accessible title, especially when
using an abbreviation. The `aria-hidden` attribute is set on the text span, because the `aria-label`
attribute is set on the container and the abbreviation is not useful for screen readers.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@use 'theme';
@use '../../tools/dictionaries';

.UNSTABLE_Avatar {
display: inline-flex;
align-items: center;
justify-content: center;
overflow: hidden;
text-decoration: none;
color: theme.$color;
border-width: theme.$border-width;
border-style: theme.$border-style;
border-color: theme.$border-color;
border-radius: theme.$border-radius;
background-color: theme.$background-color;
user-select: none;

@media (hover: hover) {
&:hover {
text-decoration: none;
color: theme.$color;
}
}
}

.UNSTABLE_Avatar--square {
border-radius: theme.$border-radius-square;
}

.UNSTABLE_Avatar > img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}

@include dictionaries.generate-sizes('UNSTABLE_Avatar', theme.$sizes);
38 changes: 38 additions & 0 deletions packages/web/src/scss/components/UNSTABLE_Avatar/_theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@use '@tokens' as tokens;
@use '../../settings/dictionaries';

$color: tokens.$text-secondary-default;
$border-width: tokens.$border-width-100;
$border-style: tokens.$border-style-100;
$border-color: tokens.$border-secondary-default;
$border-radius: 50%;
$border-radius-square: tokens.$radius-100;
$background-color: tokens.$background-cover;

$sizes: (
xsmall: (
width: tokens.$space-700,
height: tokens.$space-700,
typography: tokens.$body-xsmall-text-bold,
),
small: (
width: tokens.$space-800,
height: tokens.$space-800,
typography: tokens.$body-small-text-bold,
),
medium: (
width: tokens.$space-900,
height: tokens.$space-900,
typography: tokens.$body-medium-text-bold,
),
large: (
width: tokens.$space-1000,
height: tokens.$space-1000,
typography: tokens.$body-large-text-bold,
),
xlarge: (
width: tokens.$space-1100,
height: tokens.$space-1100,
typography: tokens.$body-xlarge-text-bold,
),
);
120 changes: 120 additions & 0 deletions packages/web/src/scss/components/UNSTABLE_Avatar/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
{{#> web/layout/plain }} {{setVar "sizes" "xsmall" "small" "medium" "large" "xlarge" }}

<section class="docs-Section">
<h2 class="docs-Heading">Icon</h2>

<div class="docs-Stack docs-Stack--start">
<div class="d-flex" style="gap: var(--spirit-space-400)">

{{#each @root.sizes as |size|}}
{{setVar "iconSize" "24"}}
{{#if (eq size "xsmall")}}
{{setVar "iconSize" "16"}}
{{/if}}
{{#if (eq size "small")}}
{{setVar "iconSize" "20"}}
{{/if}}
{{#if (eq size "large")}}
{{setVar "iconSize" "28"}}
{{/if}}
{{#if (eq size "xlarge")}}
{{setVar "iconSize" "32"}}
{{/if}}

<a href="#" class="UNSTABLE_Avatar UNSTABLE_Avatar--{{size}}" aria-label="Profile of Jiří Bárta">
<svg width="{{@root.iconSize}}" height="{{@root.iconSize}}" aria-hidden="true">
<use xlink:href="/assets/icons/svg/sprite.svg#profile" />
</svg>
</a>

{{/each}}

</div>
<div class="d-flex" style="gap: var(--spirit-space-400)">

{{#each @root.sizes as |size|}}
{{setVar "iconSize" "24"}}
{{#if (eq size "xsmall")}}
{{setVar "iconSize" "16"}}
{{/if}}
{{#if (eq size "small")}}
{{setVar "iconSize" "20"}}
{{/if}}
{{#if (eq size "large")}}
{{setVar "iconSize" "28"}}
{{/if}}
{{#if (eq size "xlarge")}}
{{setVar "iconSize" "32"}}
{{/if}}

<div class="UNSTABLE_Avatar UNSTABLE_Avatar--square UNSTABLE_Avatar--{{size}}" aria-label="Profile of Jiří Bárta">
<svg width="{{@root.iconSize}}" height="{{@root.iconSize}}" aria-hidden="true">
<use xlink:href="/assets/icons/svg/sprite.svg#profile" />
</svg>
</div>

{{/each}}

</div>
</div>
</section>

<section class="docs-Section">
<h2 class="docs-Heading">Text</h2>

<div class="docs-Stack docs-Stack--start">
<div class="d-flex" style="gap: var(--spirit-space-400)">

{{#each @root.sizes as |size|}}

<a href="#" class="UNSTABLE_Avatar UNSTABLE_Avatar--{{size}}" aria-label="Profile of Jiří Bárta">
<span aria-hidden="true">JB</span>
</a>

{{/each}}

</div>
<div class="d-flex" style="gap: var(--spirit-space-400)">

{{#each @root.sizes as |size|}}

<div class="UNSTABLE_Avatar UNSTABLE_Avatar--square UNSTABLE_Avatar--{{size}}" aria-label="Profile of Jiří Bárta">
<span aria-hidden="true">JB</span>
</div>

{{/each}}

</div>
</div>
</section>

<section class="docs-Section">
<h2 class="docs-Heading">Image</h2>

<div class="docs-Stack docs-Stack--start">
<div class="d-flex" style="gap: var(--spirit-space-400)">

{{#each @root.sizes as |size|}}

<a href="#" class="UNSTABLE_Avatar UNSTABLE_Avatar--{{size}}" aria-label="Profile of Jiří Bárta">
<img src="https://picsum.photos/id/823/162/162" alt="Jiří Bárta" aria-hidden="true" />
</a>

{{/each}}

</div>
<div class="d-flex" style="gap: var(--spirit-space-400)">

{{#each @root.sizes as |size|}}

<div class="UNSTABLE_Avatar UNSTABLE_Avatar--square UNSTABLE_Avatar--{{size}}" aria-label="Profile of Jiří Bárta">
<img src="https://picsum.photos/id/823/162/162" alt="Jiří Bárta" aria-hidden="true" />
</div>

{{/each}}

</div>
</div>
</section>

{{/ web/layout/plain }}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@forward 'UNSTABLE_Avatar';
1 change: 1 addition & 0 deletions packages/web/src/scss/components/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@
@forward 'TextField';
@forward 'Toast';
@forward 'Tooltip';
@forward 'UNSTABLE_Avatar';
@forward 'UNSTABLE_Divider';
@forward 'UNSTABLE_Slider';
4 changes: 4 additions & 0 deletions packages/web/src/scss/tools/__tests__/_dictionaries.test.scss
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@
'TestSize',
(
large: (
width: 100px,
height: 200px,
padding-y: 12px,
padding-x: 16px,
),
Expand All @@ -234,6 +236,8 @@

@include test.expect() {
.TestSize--large {
width: 100px;
height: 200px;
padding: 12px 16px;
}
}
Expand Down
12 changes: 11 additions & 1 deletion packages/web/src/scss/tools/_dictionaries.scss
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,17 @@
@mixin generate-sizes($class-name, $variables) {
@each $size, $variables in $variables {
.#{$class-name}--#{$size} {
padding: map.get($variables, padding-y) map.get($variables, padding-x);
@if map.has-key($variables, width) {
width: map.get($variables, width);
}

@if map.has-key($variables, height) {
height: map.get($variables, height);
}

@if map.has-key($variables, padding-y) and map.has-key($variables, padding-x) {
padding: map.get($variables, padding-y) map.get($variables, padding-x);
}

@if map.has-key($variables, typography) {
@include typography.generate(map.get($variables, typography));
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b9e0254

Please sign in to comment.