@import "../../resources/scss/util/variables";
@import "../../resources/scss/util/mixins";
.block-locations{
padding: 3em 0;
@include bp($lg){
padding: rem-calc(56 0 96 0);
}
.heading-row{
align-items: center;
margin-bottom: rem-calc(32);
@include bp($lg){
margin-bottom: rem-calc(56);
}
}
.heading{
font-size: rem-calc(28);
line-height: rem-calc(32);
letter-spacing: 0.02em;
font-weight: 400;
margin-bottom: 0;
@include bp($lg){
font-size: rem-calc(56);
line-height: rem-calc(64);
}
}
.location-tabs {
list-style: none;
margin: 0 0 30px 0;
padding: 0;
}
.location-tabs__nav_link {
cursor: pointer;
text-decoration: none;
}
.location-tabs__content {
display: block;
transition: opacity 0.2s;
}
.location-tabs.style__horizontal .location-tabs__content,
.location-tabs.style__vertical .location-tabs__content {
height: 0;
overflow: hidden;
opacity: 0;
visibility: hidden;
}
.location-tabs.style__horizontal .location-tabs__content.is__active,
.location-tabs.style__vertical .location-tabs__content.is__active,
.location-tabs__content.is__active {
opacity: 1;
height: auto;
visibility: visible;
}
/*------------------------------------------------------------------
3. Vertical tabs styles
-------------------------------------------------------------------*/
.location-tabs.style__vertical {
display: flex;
justify-content: space-between;
width: 100%;
}
.location-tabs.style__vertical .location-tabs__nav {
flex: 0 0 49%;
}
.location-tabs.style__vertical .location-tabs__nav .location-tabs__nav_link {
border-bottom: 1px solid $grey-secondary;
margin: rem-calc(0 0 47 0);
padding: rem-calc(0 0 17 0);
display: block;
font-weight: 400;
font-size: rem-calc(24);
line-height: rem-calc(24);
letter-spacing: 0.02em;
transition: 0.3s ease color;
&:hover{
> a{
color: $orange;
}
}
}
.location-tabs.style__vertical .location-tabs__nav .location-tabs__nav_link.is__active {
border-bottom: 1px solid $secondary;
font-weight: 600;
}
.location-tabs.style__vertical .location-tabs__content {
flex-grow: 1;
width: 0;
}
.location-tabs.style__vertical .location-tabs__content .location-tabs__nav_link {
display: none;
}
.location-tabs.style__vertical .location-tabs__content.is__active {
position: relative;
z-index: 1;
width: 100%;
@include bp($lg){
width: 50%;
padding-left: 40px;
}
}
.location-tabs.is__responsive .location-tabs__content.is__active{
border-bottom: 1px solid $secondary;
}
.location-tabs__content_wrapper{
@include bp($lg){
margin: 0 0 0 auto;
max-width: rem-calc(525);
}
}
/*------------------------------------------------------------------
4. Accordion / responsive styles
-------------------------------------------------------------------*/
.location-tabs.style__accordion,
.location-tabs.is__responsive {
display: block;
}
.location-tabs.style__accordion .location-tabs__nav,
.location-tabs.is__responsive .location-tabs__nav {
display: none;
}
.location-tabs.style__accordion .location-tabs__nav_link,
.location-tabs.is__responsive .location-tabs__nav_link,
.location-tabs.style__accordion .location-tabs__content .location-tabs__nav_link,
.location-tabs.is__responsive .location-tabs__content .location-tabs__nav_link {
display: block;
padding: 18px;
margin: -18px;
}
.location-tabs.style__accordion .location-tabs__nav_link.is__active,
.location-tabs.is__responsive .location-tabs__nav_link.is__active {
font-weight: 600;
margin-bottom: 0;
}
.location-tabs.style__accordion .location-tabs__content,
.location-tabs.is__responsive .location-tabs__content {
border-bottom: 1px solid $grey-secondary;
padding: rem-calc(0 0 17 0);
margin: rem-calc(0 0 24 0);
display: block;
height: auto;
flex: none;
opacity: 1;
visibility: visible;
overflow: hidden;
width: 100%;
&:hover{
> a{
color: $orange;
}
}
}
.location-tabs.style__accordion .location-tabs__content_wrapper,
.location-tabs.is__responsive .location-tabs__content_wrapper {
height: 0;
transform: scaleY(0);
overflow: hidden;
transition: transform 0.2s;
transform-origin: top left;
}
.location-tabs.style__accordion .location-tabs__content.is__active .location-tabs__content_wrapper,
.location-tabs.is__responsive .location-tabs__content.is__active .location-tabs__content_wrapper {
height: auto;
transform: scaleY(1);
}
/**Block map css**/
.location-map-wrapper{
width: 100%;
margin-bottom: 32px;
.location-map__map-container{
aspect-ratio: 16/9;
border-radius: 32px;
}
}
.location-contact-details{
display: flex;
flex-direction: column;
@include bp($md){
flex-direction: row;
justify-content: space-between;
}
.location-contact-col{
width: 100%;
@include bp($md){
width: 49%;
}
}
.location-contact-row{
font-size: rem-calc(18);
line-height: rem-calc(28);
letter-spacing: 0.02em;
margin-bottom: rem-calc(32);
a{
color: $black;
text-decoration: underline;
&:hover{
color: $orange;
text-decoration: none;
}
}
}
.location-contact-heading{
font-weight: 600;
}
}
}
class VanillaTabs {
constructor( opts ) {
const DEFAULTS = {
'selector': '.location-tabs',
'type': 'horizontal',
'responsiveBreak': 840,
'activeIndex' : 0
}
this.options = Object.assign( DEFAULTS, opts );
this.elems = document.querySelectorAll( this.options.selector );
// skip building tabs if they were already initialized
this.skipIfInitialized = ( tabsElem ) => {
// skip element if already initialized
if( tabsElem.classList.contains('location-tabs__initialized') ) {
return;
}
}
this.buildUI();
this.handleNavigation();
this.handleResponsive();
}
initLocationMap( block ) {
if ( ! mapboxgl ) {
console.error( mapboxgl );
return;
}
const mapContainer = block.querySelector( '.location-map__map-container' );
// Create a new token - https://account.mapbox.com/
mapboxgl.accessToken = 'pk.eyJ1Ijoic3RyYXRlZ2lxIiwiYSI6ImNsZ3Z6dXk3bzBjb3czZm11ZDV0bWd3MnUifQ.vZI6gGKApjCOMQLPqFdF_g';
let lng = parseFloat( mapContainer.getAttribute('data-lng') );
let lat = parseFloat( mapContainer.getAttribute('data-lat') );
let zoom = parseFloat( mapContainer.getAttribute('data-zoom') );
this.map = new mapboxgl.Map({
container: mapContainer,
style: 'mapbox://styles/mapbox/streets-v11',
center: [lng, lat],
zoom: zoom,
});
new mapboxgl.Marker({
color: "#FF2C31",
}).setLngLat( [lng, lat] )
.addTo( this.map );
// Add zoom and rotation controls to the map.
this.map.addControl( new mapboxgl.NavigationControl() );
}
// initialize the UI Elements
buildUI(){
let self=this;
let tabs = this.elems;
// walk on all tabs on the page
tabs.forEach( ( el, i ) => {
let tabsElem = el,
childNodes = tabsElem.childNodes,
tabsTitles = [],
tabsStyle = this.options.type;
this.skipIfInitialized( tabsElem );
tabsElem.classList.add( 'style__' + this.options.type );
tabsElem.classList.add( 'location-tabs__initialized' );
for( let i = 0; i < childNodes.length; i++ ) {
let tabItem = childNodes[i];
if ( tabItem.nodeType != Node.TEXT_NODE ) {
// add tab__content CSS class
tabItem.classList.add( 'location-tabs__content');
// grab tab title from data attribute
let tabTitle = tabItem.dataset.title ? tabItem.dataset.title : '';
tabsTitles.push( tabTitle );
// wrap tab content
let tabContent = tabItem.innerHTML;
tabItem.innerHTML = '' + tabContent + '
';
// insert nav link for accordion navigation
tabItem.insertAdjacentHTML( 'afterbegin', '' + tabTitle + '');
}
}
// create horizontal / vertical tabs navigation elements
let navElemsHTML = '';
tabsTitles.forEach( ( title ) => {
navElemsHTML = navElemsHTML + '' + title + '';
});
tabsElem.insertAdjacentHTML( 'afterbegin', '' + navElemsHTML + '');
// set initial active tab
let activeTabIndex = Number( this.options.activeIndex );
// validate active tab index. but, you can specify -1 for accordion tabs to make all of them closed by defaults
if( tabsStyle != 'accordion' && activeTabIndex != -1 ) {
if( activeTabIndex > (tabsTitles.length - 1) ) {
console.warn( 'VANILLA TABS: Active tab number from settings is bigger than tabs count. Please remember, that index starts from Zero! To avoid crashes, activeIndex option was reverted to 0.');
activeTabIndex = 0;
}
tabsElem.querySelectorAll( '.location-tabs__nav > .location-tabs__nav_link')[ activeTabIndex ].classList.add( 'is__active' );
tabsElem.querySelectorAll( '.location-tabs__content')[ activeTabIndex ].classList.add( 'is__active' );
tabsElem.querySelectorAll( '.location-tabs__content > .location-tabs__nav_link')[ activeTabIndex ].classList.add( 'is__active' );
setTimeout(function() {
self.initLocationMap(tabsElem.querySelectorAll( '.location-tabs__content')[ activeTabIndex ]);
}, 800);
}
});
}
// navigation: assign click events
handleNavigation() {
let self = this;
let tabs = this.elems,
tabsStyle = this.options.type;
// walk on all tabs on the page
tabs.forEach( ( el, i ) => {
let tabsElem = el;
this.skipIfInitialized( tabsElem );
tabsElem.addEventListener( 'click', ( e ) => {
if( e.target && e.target.classList.contains( 'location-tabs__nav_link') ) {
e.preventDefault();
let activeTabIndex;
// if we click on main navigation link
if( e.target.parentElement.classList == 'location-tabs__nav' ) {
activeTabIndex = Array.prototype.slice.call( e.target.parentElement.children ).indexOf( e.target );
// if we click on accordion nav link
} else {
activeTabIndex = Array.prototype.slice.call( e.target.parentElement.parentElement.children ).indexOf( e.target.parentElement ) - 1;
}
let tabsContent = tabsElem.getElementsByClassName( 'location-tabs__content'),
mainNavLinks = tabsElem.querySelectorAll( '.location-tabs__nav > .location-tabs__nav_link'),
accordionNavLinks = tabsElem.querySelectorAll( '.location-tabs__content > .location-tabs__nav_link');
// toggle accordion panel
if( ( tabsStyle == 'accordion' || tabsElem.classList.contains( 'is__responsive') ) && e.target.classList.contains( 'is__active') ) {
tabsContent[ activeTabIndex ].classList.remove( 'is__active');
mainNavLinks[ activeTabIndex ].classList.remove( 'is__active');
accordionNavLinks[ activeTabIndex ].classList.remove( 'is__active');
return;
}
// remove active class for inactive tabs
for( let i = 0; i < tabsContent.length; i++ ) {
tabsContent[ i ].classList.remove( 'is__active');
}
// add active class for a current (active) tab
tabsContent[ activeTabIndex ].classList.add( 'is__active');
// add active classes and remove inactive for main nav links
mainNavLinks.forEach( ( el ) => {
el.classList.remove( 'is__active');
});
mainNavLinks[ activeTabIndex ].classList.add( 'is__active');
if( window.innerWidth <= Number( this.options.responsiveBreak ) ) {
$('html, body').animate({
scrollTop: tabsContent[ activeTabIndex ].offsetTop - ($('.site-header').height() + 74)
}, 0);
}
// add active classes and remove inactive for accordion nav links
accordionNavLinks.forEach( ( el ) => {
el.classList.remove( 'is__active');
});
accordionNavLinks[ activeTabIndex ].classList.add( 'is__active');
self.initLocationMap(tabsContent[ activeTabIndex ]);
}
});
});
}
// responsive: tabs to accordion
handleResponsive() {
let tabs = this.elems,
responsiveClassName = 'is__responsive',
tabsStyle = this.options.type;
window.addEventListener( 'resize', () => {
// walk on all tabs on the page
tabs.forEach( ( el, i ) => {
let tabsElem = el,
tabsContent = tabsElem.getElementsByClassName( 'location-tabs__content'),
mainNavLinks = tabsElem.querySelectorAll( '.location-tabs__nav > .location-tabs__nav_link'),
accordionNavLinks = tabsElem.querySelectorAll( '.location-tabs__content > .location-tabs__nav_link');
this.skipIfInitialized( tabsElem );
if( window.innerWidth > Number( this.options.responsiveBreak ) ) {
tabsElem.classList.remove( responsiveClassName );
if( tabsStyle != 'accordion' ) {
// set first active tab if all of tabs were closed in accordion mode
let openTabs = tabsElem.querySelectorAll( '.location-tabs__nav_link.is__active');
if( openTabs.length == 0 ) {
tabsContent[0].classList.add('is__active');
mainNavLinks[0].classList.add('is__active');
accordionNavLinks[0].classList.add('is__active');
}
}
} else {
tabsElem.classList.add( responsiveClassName );
}
});
});
// manually fire resize event
window.dispatchEvent( new Event( 'resize' ));
}
}
class LocationsBlock {
/**
* Create and initialise objects of this class
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor
* @param {object} block
*/
constructor() {
this.blocks = document.querySelectorAll('.block-locations');
this.mapBlocks = document.querySelectorAll('.location-map-wrapper');
this.init();
}
init() {
new VanillaTabs({
'selector': '.location-tabs', // default is ".tabs"
'type': 'vertical', // can be horizontal / vertical / accordion
'responsiveBreak': 996, // tabs become accordion on this device width
'activeIndex' : 0 // active tab index (starts from 0 ). Can be -1 for accordions.
});
}
}
new LocationsBlock();
This component is not currently used on any pages.