Header a moduly
Header
{* Header *}
<header class="header header--top js--header js--fixed-header">
<div class="header__content --content --flex">
{* Header | Top *}
<div class="header__top --flex-centre-y">
{* Header | Logo *}
<div class="header__logo --flex-inline">
<a class="header__logo-link" href="/{$lang}">
<img class="header__logo-img" src="/img/logo.svg"
alt="{$web['DEFAULT_TITLE']}">
</a>
</div>
{* Header | Menu *}
<div class="header__menu">
{include 'menu.latte', nav => $nav}
</div>
{* Header | Call *}
{include "./header-call.latte"}
{* Header | Language *}
<div class="header__lang --flex-inline --flex-centre-y" n:if="count($activeLangs) > 1">
{include 'lang.latte'}
</div>
</div>
{* Header | Bottom *}
<div class="header__bottom --flex-inline --flex-centre-y">
<div class="--w-12 --w-l-3 header__column header__column--left header__desktop-part">
<a href="#" class="header__button
js--toggler button button--brand" data-target="#menuDesktop">
<div class="header__button-bar-wrap">
<span class="header__button-bar"></span>
<span class="header__button-bar"></span>
<span class="header__button-bar"></span>
</div>
{$web['HEADER_CHOOSE_CATEGORY']}
</a>
{* Header | Menu *}
<div n:class="'header__menu js--header-menu', $menuExpanded ? 'js--active'" id="menuDesktop">
{include 'menu.latte', nav => $categories}
</div>
</div>
<div class="--w-12 --w-l-9 --flex
header__column header__column--right">
{* Header | Search *}
<div class="header__search header__desktop-part --flex-inline --flex-centre-y icon icon--search">
{form search class => "header__search-form form form--search"}
<input n:name="search_text"
data-use="typeahead"
placeholder="{$web['SEARCH_PLACEHOLDER']}"
class="form__input"
type="text">
<button class="button form__button js--header-search">
{$web['HEADER_SEARCH']}
</button>
{/form}
</div>
{* Header | Logo *}
<div class="header__logo --flex-inline header__mobile-part">
<a class="header__logo-link" href="/{$lang}">
<img class="header__logo-img" src="/img/logo.svg"
alt="{$web['DEFAULT_TITLE']}">
</a>
</div>
{* Header | Search *}
<div class="header__search-toggle --flex-inline --flex-centre-y header__desktop-part">
<button class="header__search-toggle-button icon icon--search --hide-text js--header-search-toggle">
{$web['HEADER_SEARCH']}
</button>
</div>
{* Header | Login *}
{include "./login.latte"}
{* Header | Basket *}
<basket></basket>
<div class="header__mobile-part">
<a href="#" class="header__button js--toggler
button button--brand" data-target="#menuMobile">
<div class="header__button-bar-wrap">
<span class="header__button-bar"></span>
<span class="header__button-bar"></span>
<span class="header__button-bar"></span>
</div>
Menu
</a>
{* Header | Menu *}
<div n:class="'header__menu js--header-menu'"
id="menuMobile">
{include 'menu.latte', nav => $categories, secondaryNav => $nav}
</div>
</div>
</div>
<div class="--w-12 header__mobile-part">
<div class="header__search --flex-inline --flex-centre-y icon icon--search">
{form search class => "header__search-form form form--search"}
<input n:name="search_text"
data-use="typeahead"
placeholder="{$web['SEARCH_PLACEHOLDER']}"
class="form__input"
type="text">
<button class="button form__button js--header-search">
{$web['HEADER_SEARCH']}
</button>
{/form}
</div>
</div>
</div>
</div>
</header>
.header {
background: $color__header;
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: 100;
overflow: visible;
border-bottom: 1px solid $color__gray;
padding-bottom:25px;
}
.header--fixed{
position: fixed;
left:0;
top:0;
right:0;
}
.header--hide {
top: -100%;
}
.header__menu{
position: relative;
.header__bottom &{
max-height: 0px;
transition: max-height 0.3s ease-in-out;
overflow: hidden;
right: -16px;
left: -16px;
@include media($large){
left: 0;
right: auto;
}
}
}
.header__menu{
.header__top &{
display: none;
@include media($large){
display: flex;
}
}
.header__bottom &{
position: absolute;
z-index: 4;
@include media($large){
width: 100%;
}
}
}
.header__mobile-part{
display: initial;
@include media($large){
display: none;
}
}
.header__desktop-part{
display: none;
@include media($large){
display: initial;
}
}
.header__call{
white-space: nowrap;
margin-right: 15px;
line-height: 1.2;
@include media($large){
margin-left: auto;
}
.header__top &{
display: none;
@include media($large){
display: flex;
}
}
}
.header__call-link{
color: $color__green;
margin-right: 8px;
&::before{
font-size: 1.3rem;
}
}
.header__call-content{
flex-direction: column;
@include media($large){
flex-direction: row;
}
}
.header__call-text{
color: $color__gray-darker;
display: block;
}
.header__logo{
width: 110px;
margin-right:15px;
@include media(375px){
width: 130px;
}
@include media($large){
margin-right: 25px;
}
@include media($xlarge){
margin-right: 40px;
width: 190px;
}
}
.header__bottom{
align-items: center;
width: 100%;
}
.header__top{
padding: 25px 0;
font-size: 1.4rem;
display: none;
width: 100%;
@include media($large){
display: flex;
}
}
.header__button{
width: 100%;
flex-direction: row;
padding: 4px 11px;
@include media(375px){
padding: 8px 17px;
}
@include media($large){
padding: 8px 32px;
}
}
.header__button-bar-wrap{
margin-right: 10px;
pointer-events: none;
}
.header__button-bar{
display: block;
background: white;
width: 18px;
height: 2px;
&:not(:last-of-type){
margin-bottom: 3px;
}
}
.header__search{
width: 100%;
position: relative;
max-width: 525px;
&::before{
position: absolute;
left: 18px;
top: 19px;
color: $color__primary;
font-size: 1.6rem;
}
@include media($xlarge){
max-width: 665px;
}
}
.header__search-form{
width: 100%;
display:flex;
}
.header__column{
position:relative;
}
.header__column--right{
align-items: center;
padding: 15px 0;
@include media($large){
padding: 0 0 0 55px;
}
}
.header__login{
display: flex;
align-items: center;
margin-right: 10px;
margin-left: auto;
color: $color__text;
@include media($large){
margin-right: 25px;
}
}
Menu
<nav class="menu">
{default $secondaryNav = false}
{* Menu | List *}
<div class="menu__content --flex --flex-centre js--menu-content">
<div class="menu__list">
<div class="menu__top">
{* Header | Call *}
{include "./header-call.latte"}
{* Header | Lang *}
{include "./lang.latte"}
</div>
{foreach $nav as $item}
<div class="menu__item">
<a n:class="'menu__link', $iterator->isLast() ? 'menu__link--last'" href="{$item|link|noescape}">
{$item|name|striptags}
</a>
</div>
{/foreach}
</div>
<div class="menu__additional-list --flex --flex-column" n:if="$secondaryNav">
{foreach $secondaryNav as $item}
<div class="menu__additional-item">
<a n:class="'menu__additional-link', $iterator->isLast() ? 'menu__link--last'" href="{$item|link|noescape}">
{$item|name|striptags}
</a>
</div>
{/foreach}
</div>
</div>
</nav>
.menu__list {
display: flex;
.header__bottom & {
background: $color__gray;
flex-direction: column;
position: relative;
padding: 6px 15px;
font-size: 1.5rem;
margin-top: 15px;
width: 100%;
max-height: calc(100vh - 250px);
overflow-y: auto;
@include media($large){
padding: 6px 30px;
max-height: calc(100vh - 200px);
}
&::before {
@include pseudo();
bottom: 100%;
width: 0;
height: 0;
border-style: solid;
border-width: 0 16px 11px 16px;
border-color: transparent transparent $color__gray transparent;
right: 54px;
@include media($large) {
left: calc(50% - 16px);
right: auto;
}
}
}
}
.menu__top{
display: flex;
justify-content: space-between;
align-items: center;
padding:15px 0 8px;
flex-shrink: 0;
@include media($large){
display: none;
}
}
.menu__additional-list {
background: $color__gray;
width: 100%;
padding: 35px 15px;
max-height: 150px;
}
.menu__additional-link{
padding: 10px 0;
text-transform:uppercase;
font-size: 1.4rem;
color: $color__text;
}
.menu__list--main {
display: flex;
}
.menu__button {
display: inline-block;
height: 36px;
padding: 3px;
position: absolute;
right: 8px;
top: -4px;
width: 40px;
z-index: 1;
@include media($large) {
display: none;
}
}
.menu__link {
color: $color__text;
display: block;
&:hover, &:focus {
color: $color__primary;
}
.header__top & {
font-size: 1.4rem;
text-transform: uppercase;
padding: 3px 8px;
@include media($xlarge) {
padding: 5px 13px;
}
}
.header__bottom & {
width: 100%;
padding: 9.65px 2px;
@include media($xlarge) {
padding: 12.3px 2px;
}
border-bottom: 1px solid $color__border;
}
}
.menu__link--last {
.header__bottom & {
border-bottom: 0;
}
}
Header-call
<div class="header__call --flex-centre-y">
<div class="header__call-content --flex --flex-nowrap">
<a class="header__call-link --flex --flex-centre icon icon--phone"
href="tel:{$web['PER_PHONE']}
{$web['PHONE']}">
<span>{$web['PER_PHONE']} <b>{$web['PHONE']}</b></span>
</a>
<span class="header__call-text">
{$web['OPEN_HOURS']|noescape}
</span>
</div>
</div>
Lang
{* Lang *}
<div class="lang" n:if="count($activeLangs) > 1">
{* Lang | List *}
<ul class="lang__list --flex --flex-nowrap ">
<li n:class="'lang__item', $activeLangId === $lang_id ? 'lang__item--selected'"
n:foreach="$activeLangs as $activeLangId => $activeLang">
<a class="lang__link --flex --flex-nowrap --flex-y-centre" role="button" title="{$activeLang}" href="/{$activeLang}">
<img src="/img/flags/{$activeLang}.svg" alt="{$activeLang}">
</a>
</li>
</ul>
</div>
.lang{
.header__top &{
display: none;
@include media($large){
display: block;
}
}
}
.lang__item{
opacity: 0.4;
transition: opacity $ease;
&:not(:last-of-type){
margin-right: 8px;
}
&:hover, &:focus{
opacity: 1;
}
}
.lang__item--selected{
opacity: 1;
}
Login
<div class="header__login js--login login"
data-target=".js--login-wrap">
<span class="login__icon icon icon--user"></span>
<div class="login__wrap js--login-wrap">
<div class="login__box --flex --flex-column --flex-end">
{if $user->isLoggedIn()}
<a class="login__link --link-underline"
href="/{$lang}/account/orders">{$web['ACCOUNT_ORDERS']}</a>
<a class="login__link --link-underline"
href="/{$lang}/account/address">{$web['ACCOUNT_ADDRESS']}</a>
<a class="login__link --link-underline"
href="/{$lang}/account/setting">{$web['ACCOUNT_SETTING']}</a>
<a class="login__link --link-underline"
href="/{$lang}/logout">{_front.layout.logout}</a>
{else}
{form signInForm class => "login__form form form--contact"}
<label class="form__label" n:name="$form['email']">
{_}{$form['email']->caption}{/_}
{input email class => "form__input"}
</label>
<label class="form__label" n:name="$form['password']">
{_}{$form['password']->caption}{/_}
{input password class => "form__input"}
</label>
<label>
{input send class => "--hide"}
<span class="form__button button button--brand">
{_}{$form['send']->caption}{/_}
</span>
</label>
{/form}
<a class="login__link --link-underline" href="/{$lang}/register">{$web['LOGIN_REGISTER']}</a>
<a class="login__link --link-underline" href="/{$lang}/password">{$web['LOGIN_FORGOTTEN_PASS']}</a>
{/if}
</div>
</div>
</div>
.login{
position: relative;
cursor:pointer;
}
.login__form{
width: 100%;
margin: 0 0 10px 0;
}
.login__icon{
&:hover, &:focus{
color: $color__primary;
}
&::before{
font-size: 2.1rem;
@include media(375px){
font-size: 2.6rem;
}
}
}
.login__wrap{
position: absolute;
background: #fff;
right: -92px;
top: 100%;
width: 290px;
z-index: 2;
max-height: 0px;
overflow: hidden;
transition: max-height $ease;
@include media(375px){
right: -107px;
}
@include media($large){
right: 0px;
}
}
.login__box{
padding: 10px;
border: 1px solid $color__gray;
}
.login__title{
width: 100%;
font-size: 1.5rem;
}
Potřebný javascript
const headerBasket = document.querySelector(".js--basket");
headerBasket.addEventListener("mouseenter", function (e) {
collapseElement(headerBasket.dataset.target, 'show');
})
headerBasket.addEventListener("mouseleave", function (e) {
collapseElement(headerBasket.dataset.target, 'hide');
})
const headerLogin = document.querySelector(".js--login");
headerLogin.addEventListener("mouseenter", function (e) {
collapseElement(headerLogin.dataset.target, 'show');
})
headerLogin.addEventListener("mouseleave", function (e) {
collapseElement(headerLogin.dataset.target, 'hide');
})
}
const collapseFnMap = {
'toggle': 'toggle',
'show': 'add',
'hide': 'remove'
};
function collapseElement(selector, cmd = 'toggle') {
let target = document.querySelector(selector);
if(cmd === 'toggle'){
if (target.classList.contains("js--active")) {
target.style.maxHeight = "0px";
} else {
target.style.maxHeight = target.scrollHeight + "px";
}
}
else if(cmd === 'show'){
target.style.maxHeight = target.scrollHeight + "px";
}
else if(cmd === 'hide'){
target.style.maxHeight = "0px";
}
target.classList[collapseFnMap[cmd]]('js--active');
}