<div class="profile">
<button class="profile__toggle js-profile-toggle" type="button">
<span class="profile__toggle-inner">
<span class="grid grid--no-wrap">
<span class="grid__col grid__col--max">
<span class="profile__role">NOPE kliendihaldur</span>
<span class="profile__name text-small">
<span class="profile__name-inner">
Kaarel Nurmsalu
</span>
</span>
</span>
<span class="grid__col grid__col--min">
<svg class="icon profile__icon" focusable="false">
<use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#chevron-bottom"></use>
</svg>
</span>
</span>
</span>
</button>
<div class="profile__content text-small">
<div class="profile__content-inner">
<div class="grid grid--no-wrap grid--equalheight">
<div class="grid__col grid__col--min">
<figure class="image image--full image--round profile__image">
<img loading="lazy" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2048%2048%22%3E%3C%2Fsvg%3E" data-srcset="//via.placeholder.com/100x100 100w, //via.placeholder.com/200x200 200w, //via.placeholder.com/300x300 300w, //via.placeholder.com/400x400 400w, //via.placeholder.com/500x500 500w, //via.placeholder.com/600x600 600w, //via.placeholder.com/700x700 700w, //via.placeholder.com/800x800 800w, //via.placeholder.com/48x48 48w, //via.placeholder.com/96x96 96w" data-sizes="auto" alt="" class="image__img lazyload">
</figure>
</div>
<div class="grid__col grid__col--max">
<div class="profile__data">
<div class="profile__role">NOPE kliendihaldur</div>
<span class="profile__name">Kaarel Nurmsalu</span> <a class="profile__phone" href="tel:+372 53 453 833">+372 53 453 833</a><br> <a class="profile__email" href="mailto:kaarel.nurmsalu@ramirent.ee">kaarel.nurmsalu@ramirent.ee</a>
</div>
</div>
</div>
</div>
</div>
</div>
{% set BEM -%}
profile
{%- if modifier %} {{ modifier }}{% endif %}
{%- if class %} {{ class }}{% endif %}
{% endset %}
<div class="{{ BEM }}">
<button class="profile__toggle js-profile-toggle" type="button">
<span class="profile__toggle-inner">
<span class="grid grid--no-wrap">
<span class="grid__col grid__col--max">
<span class="profile__role">{{ data.role }}</span>
{% if data.name %}
<span class="profile__name text-small">
<span class="profile__name-inner">
{{ data.name }}
</span>
</span>
{% endif %}
</span>
<span class="grid__col grid__col--min">
{% include '@icon' with { modifier: '', class: 'profile__icon', name: 'chevron-bottom' } %}
</span>
</span>
</span>
</button>
<div class="profile__content text-small">
<div class="profile__content-inner">
<div class="grid grid--no-wrap grid--equalheight">
{% if data.image %}
<div class="grid__col grid__col--min">
{% include '@image' with {
data: data.image|srcset('48x48'),
class: 'profile__image',
modifier: 'image--full image--round',
} %}
</div>
{% endif %}
<div class="grid__col grid__col--max">
<div class="profile__data">
<div class="profile__role">{{ data.role }}</div>
{% if data.name %}<span class="profile__name">{{ data.name }}</span>{% endif %}
{% if data.phone %}<a class="profile__phone" href="tel:{{ data.phone }}">{{ data.phone }}</a><br>{% endif %}
{% if data.email %}<a class="profile__email" href="mailto:{{ data.email }}">{{ data.email }}</a>{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
{
"language": "en-US",
"data": {
"role": "NOPE kliendihaldur",
"name": "Kaarel Nurmsalu",
"phone": "+372 53 453 833",
"email": "kaarel.nurmsalu@ramirent.ee",
"image": true
}
}
.profile {
color: $L-text-inverted;
}
.profile__toggle {
display: block;
width: 100%;
padding: 0;
background: transparent;
border: none;
color: $L-text-inverted;
outline: none;
-webkit-appearance: none;
text-align: left;
cursor: pointer;
html[data-whatinput='keyboard'] &:focus {
outline: 1px solid $L-text-inverted;
outline-offset: 2px;
}
@include bp(sm-min) {
display: none;
}
}
.profile__toggle-inner {
display: block;
}
.profile__content {
opacity: 0;
visibility: hidden;
max-height: 0;
overflow: hidden;
transition: opacity $transition-duration $transition-easing,
visibility $transition-duration $transition-easing,
max-height $transition-duration $transition-easing;
@include bp(sm-min) {
opacity: 1;
visibility: visible;
max-height: none;
overflow: visible;
}
.profile.is-opening & {
opacity: 1;
visibility: visible;
}
.profile.is-closing & {
opacity: 0;
visibility: hidden;
}
.profile.is-open & {
opacity: 1;
visibility: visible;
max-height: none;
overflow: visible;
}
}
.profile__role {
display: block;
font-size: $font-size-small;
font-weight: $font-weight-bold;
letter-spacing: $letter-spacing-default;
line-height: $line-height-small;
.profile__content & {
display: none;
@include bp(sm-min) {
display: block;
}
}
}
.profile__icon {
flex: 0 0 24px;
font-size: 24px;
transition: transform $transition-duration-s $transition-easing;
.profile.is-opening &,
.profile.is-open & {
transform: rotate(180deg);
}
}
.profile__image {
width: 48px;
height: 48px;
@include bp(sm-min) {
align-self: flex-end;
}
}
.profile__phone,
.profile__email {
color: $L-text-inverted;
text-decoration: none;
&:hover,
&:focus,
&:active {
color: $L-text-inverted;
}
}
.profile__name {
display: block;
.profile__toggle & {
overflow: hidden;
transition: opacity $transition-duration $transition-easing,
visibility $transition-duration $transition-easing,
max-height $transition-duration $transition-easing;
.profile.is-open &,
.profile.profile.is-opening & {
opacity: 0;
visibility: hidden;
}
.profile.is-open & {
max-height: 0;
}
}
}
.profile__name-inner {
display: block;
padding-top: 8px;
}
import Component from '../component/component';
import './profile.scss';
export interface IProfileSettings {
animationDuration?: number;
closingClass?: string;
contentSelector?: string;
nameSelector?: string;
openClass?: string;
openingClass?: string;
toggleSelector?: string;
}
export const profileSettings: IProfileSettings = {
animationDuration: 300,
closingClass: 'is-closing',
contentSelector: '.profile__content',
nameSelector: '.profile__name',
openClass: 'is-open',
openingClass: 'is-opening',
toggleSelector: '.js-profile-toggle',
};
export default class Profile extends Component {
static initSelector: string = '.profile';
content: JQuery<HTMLElement>;
inner: JQuery<HTMLElement>;
isOpen: boolean;
name: JQuery<HTMLElement>;
timeout: number;
nameTimeout: number;
toggleButton: JQuery<HTMLElement>;
settings: IProfileSettings;
constructor(target: HTMLElement) {
super(target);
this.settings = profileSettings;
this.content = this.element.find(this.settings.contentSelector);
this.inner = this.content.children().first();
this.isOpen = false;
this.toggleButton = this.element.find(this.settings.toggleSelector);
this.name = this.toggleButton.find(this.settings.nameSelector);
this.toggleButton.on('click', this.handleClick.bind(this));
}
handleClick(): void {
this.toggle();
}
toggle(): void {
this.isOpen = !this.isOpen;
if (this.isOpen) {
this.element.addClass(this.settings.openingClass);
this.open(this.content);
this.hideName();
} else {
this.element.addClass(this.settings.closingClass);
this.close(this.content);
this.showName();
}
}
open(el: JQuery<HTMLElement>): void {
el.css({
maxHeight: this.inner.innerHeight(),
});
clearTimeout(this.timeout);
this.timeout = window.setTimeout(() => {
el.removeAttr('style');
this.element.removeClass(this.settings.openingClass);
this.element.addClass(this.settings.openClass);
}, this.settings.animationDuration);
}
close(el: JQuery<HTMLElement>): void {
el.css({
maxHeight: this.inner.innerHeight(),
});
this.element.removeClass(this.settings.openClass);
clearTimeout(this.timeout);
this.timeout = window.setTimeout(() => {
el.css({
maxHeight: 0,
});
clearTimeout(this.timeout);
this.timeout = window.setTimeout(() => {
el.removeAttr('style');
this.element.removeClass(this.settings.closingClass);
}, this.settings.animationDuration);
}, 10);
}
hideName(): void {
const inner: JQuery<HTMLElement> = this.name.children().first();
this.name.css({
maxHeight: inner.outerHeight(),
});
clearTimeout(this.nameTimeout);
this.nameTimeout = window.setTimeout(() => {
this.name.css({
maxHeight: 0,
});
clearTimeout(this.nameTimeout);
this.nameTimeout = window.setTimeout(() => {
this.name.removeAttr('style');
}, this.settings.animationDuration);
}, 10);
}
showName(): void {
const inner: JQuery<HTMLElement> = this.name.children().first();
this.name.css({
maxHeight: inner.outerHeight(),
});
clearTimeout(this.nameTimeout);
this.nameTimeout = window.setTimeout(() => {
this.name.removeAttr('style');
}, this.settings.animationDuration);
}
}