Problem/Motivation
Maybe it's not the best place to post this, but I want to mention a use case for howto create a component not included in radix. So is more a documentation issue...
In your subtheme generate the component with drupal-radix-cli. In this case avatar component, it will create the avatar directory in components/, here are the contents:
avatar.component.yml , is where the properties and slots are defined, later in avatar.twig template, these properties will be used as twig variables, and slots as twig blocks.
$schema: https://git.drupalcode.org/project/drupal/-/raw/10.1.x/core/modules/sdc/src/metadata.schema.json
name: avatar
status: experimental
description: 'The avatar component auto-generated by drupal-radix-cli'
slots:
image:
title: Image
props:
type: object
properties:
size:
title: Size
description: "It is possible to set the size of avatars."
enum:
- avatar-xs
- avatar-sm
- avatar-lg
- avatar-xl
- avatar-xxl
square:
title: Square
description: "Disables rounding of the avatar, rending the avatar with square corners."
type: "boolean"
image_element:
title: "Image element"
description: "The html image element"
type: "string"
profile:
title: "profile"
description: "The profile object to feed avatar"
type: object
text_color:
title: "Text color"
description: "The color that will be used for text"
type: string
variant:
title: "variant"
description: "Use the variant prop to specify one of Bootstrap theme variant colors. The default variant is secondary."
enum:
- secondary
- primary
- dark
- light
- success
- danger
- warning
- info
text:
title: text
description: "Text that will be in avatar if not using image."
type: "string"
avatar_url:
title: "Avatar url"
description: "The url to point"
type: string
stories:
preview:
title: Preview
props:
size: w-24
square: false
image_element: "<img src='https://placekitten.com/300/300' />"
avatar.twig , take care with scope, as properties are inherited, so using for example 'attributes' here will be risky if the parent template uses 'attributes' variable name too.
{#
/**
* @file
* Template for avatar component.
*/
#}
{% set avatar_attributes = create_attribute() %}
{% set avatar_attributes = avatar_attributes.addClass(['avatar', 'not-prose']) %}
{% set link_attributes = create_attribute() %}
{% if size %}
{% set avatar_attributes = avatar_attributes.addClass(size) %}
{% endif %}
{% if square %}
{% set avatar_attributes = avatar_attributes.addClass(square) %}
{% endif %}
{% if image_element %}
{% set image_element_local = image_element %}
{% endif %}
{% if profile %}
{% if profile.user_picture %}
{% set image_element_local = profile.user_picture %}
{% endif %}
{% set entity = profile.entity %}
{% set text_local = profile.entity.label|first|upper %}
{% set link_attributes = link_attributes.setAttribute('href', path('entity.user.canonical', {'user': profile.entity.id })).setAttribute('title', profile.entity.label) %}
{% endif %}
{% if variant %}
{% set variant_local = variant %}
{% else %}
{% set variant_local = "secondary" %}
{% endif %}
{% set avatar_attributes = avatar_attributes.addClass('bg-' ~ variant_local ) %}
{% if text_color %}
{% set avatar_attributes = avatar_attributes.addClass( text_color ) %}
{% set link_attributes = link_attributes.addClass( text_color ) %}
{% endif %}
{% if text %}
{% set text_local = text %}
{% endif %}
{% if avatar_url %}
{% set link_attributes = link_attributes.setAttribute('href', avatar_url) %}
{% endif %}
<a {{ link_attributes }}>
<div {{ avatar_attributes }}>
{% if image_element_local %}
<div class="avatar-img">
{% block image %}
{{ image_element_local }}
{% endblock %}
</div>
{% else %}
{% if text_local %}
{{ text_local }}
{% else %}
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-fill" viewBox="0 0 16 16">
<path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6"/>
</svg>
{% endif %}
{% endif %}
</div>
</a>
Previous to talk about avatar.scss , we want to declare the enumeration of sizes, this is done in subtheme src/scss/_variables.scss :
$avatar-width: 32px !default;
$avatar-values: (
xs: 16px,
sm: 24px,
lg: 40px,
xl: 96px,
xxl: 128px,
) !default;
finally the avatar.scss , the last rule will declare the sizes rules to generate the avatar sizes.
@import "../../src/scss/init";
// Avatar custom styles
.avatar {
display: inline-flex;
align-items: center;
justify-content: center;
vertical-align: middle;
flex-shrink: 0;
width: var(--#{$prefix}avatar-width);
height: var(--#{$prefix}avatar-width);
font-size: inherit;
font-weight: 400;
line-height: 1;
max-width: 100%;
max-height: auto;
text-align: center;
overflow: hidden;
position: relative;
border-radius: 50%;
margin-bottom: 0 !important;
&.avatar-sm {
width: 2.5rem;
height: 2.5rem;
border-radius: 2.5rem;
}
&.avatar-lg {
width: 3.5rem;
height: 3.5rem;
border-radius: 3.5rem;
}
&.square {
border-radius: 0;
}
&:focus {
outline: 0;
}
&.btn,
&[href] {
padding: 0;
border: 0;
.avatar-img img {
transition: transform 0.15s ease-in-out;
}
&:not(:disabled):not(.disabled) {
cursor: pointer;
&:hover {
.avatar-img img {
transform: scale(1.15);
}
}
}
}
&.disabled,
&:disabled,
&[disabled] {
opacity: $btn-disabled-opacity;
pointer-events: none;
}
.avatar-custom,
.avatar-text,
.avatar-img {
border-radius: inherit;
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
// https://gist.github.com/ayamflow/b602ab436ac9f05660d9c15190f4fd7b
mask-image: radial-gradient(white, black);
}
.avatar-text {
text-transform: uppercase;
white-space: nowrap;
}
&[href] {
text-decoration: none;
}
> .icon {
width: 60%;
height: auto;
max-width: 100%;
}
.avatar-img .field--name-user-picture {
margin: 0;
img {
width: 100%;
height: 100%;
max-height: auto;
border-radius: inherit;
// This is not supported in IE11 and Edge <16
// https://caniuse.com/object-fit
object-fit: cover;
}
}
}
.avatar-group {
display: flex;
.avatar {
margin-right: calc(-.4 * 2.5rem);
}
.avatar:hover {
margin-right: 0px;
}
.avatar:last-child {
margin-right: 0;
}
}
@each $name, $width in $avatar-values {
.avatar-#{$name} {
--#{$prefix}avatar-width: #{$width};
}
}
In this component js is not used.
With this component it could be used with in any template:
{% embed 'radix_yoursubtheme:avatar' with { 'size': 'avatar-sm', 'profile': avatar, 'image_element': avatar.user_picture, 'variant': 'warning' , 'text_color': 'text-white' } %}
{% endembed %}
In this example an array of
$vars['avatar'] = [ 'user_picture': 'rendered user entity using compact view mode', 'entity' : UserEntity ]
could be used to feed the component.