Add tabs feature with two options
This commit is contained in:
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
66
mobile-scrollbar/index.xslt
Normal file
66
mobile-scrollbar/index.xslt
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?><iai:component><iai:componentsdata><cdata-start/>
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tabs__container">
|
||||||
|
|
||||||
|
<!--Opis-->
|
||||||
|
<iaixsl:if test="page/projector/product/vlongdescription and not(page/projector/product/vlongdescription = '')">
|
||||||
|
<div class="tabs__item idm-active" data-tab="projector_longdescription">
|
||||||
|
<iai:variable vid="Opis produktu" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Parametry-->
|
||||||
|
<iaixsl:if
|
||||||
|
test="/shop/page/projector/product/price/@srp or (count(/shop/page/projector/product/dictionary/items) > 0) or ($product_producer_label and not(/shop/page/projector/product/firm/@name = '')) or ($product_code_label and /shop/page/projector/product/@code) or ($product_series_label and /shop/page/projector/product/series) or ($product_producer_code_label and count(/shop/page/projector/product/sizes/size[@code_producer and not(@code_producer = '')]) > 0) or (count(/shop/page/projector/product/responsible_entity/producer | /shop/page/projector/product/responsible_entity/persons/person) > 0)"
|
||||||
|
>
|
||||||
|
<div class="tabs__item" data-tab="projector_dictionary">
|
||||||
|
<iai:variable vid="Parametry techniczne" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Do pobrania-->
|
||||||
|
<iaixsl:if
|
||||||
|
test="(/shop/page/projector/product/enclosures/documents/item) or (/shop/page/projector/product/enclosures/audio/item) or (/shop/page/projector/product/enclosures/other) or (/shop/page/projector/product/enclosures/images_attachments/item) or (/shop/page/projector/product/enclosures/video/item)"
|
||||||
|
>
|
||||||
|
<div class="tabs__item" data-tab="projector_enclosures">
|
||||||
|
<iai:variable vid="Do pobrania" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Gwarancja-->
|
||||||
|
<iaixsl:if test="page/projector/product/warranty and not(page/projector/product/warranty= '')">
|
||||||
|
<div class="tabs__item" data-tab="projector_warranty">
|
||||||
|
<iai:variable vid="Gwarancja" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Pytania-->
|
||||||
|
<iaixsl:if test="page/projector/product/warranty and not(page/projector/product/warranty= '')">
|
||||||
|
<div class="tabs__item" data-tab="product_questions_list">
|
||||||
|
<iai:variable vid="Pytania" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Opinie-->
|
||||||
|
<div class="tabs__item" data-tab="opinions_section">
|
||||||
|
<iai:variable vid="Opinie" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--Blog-->
|
||||||
|
<iaixsl:if test="count(/shop/page/projector/blog_entries/item) > 0">
|
||||||
|
<div class="tabs__item" data-tab="projector_blog">
|
||||||
|
<iai:variable vid="Blog" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Rekomendacje 1-->
|
||||||
|
<iaixsl:if test="page/projector/products_associated_zone1">
|
||||||
|
<div class="tabs__item" data-tab="products_associated_zone1">
|
||||||
|
<iai:variable vid="Rekomendacje 1" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<cdata-end/></iai:componentsdata></iai:component>
|
||||||
26
mobile-scrollbar/src/main.js
Normal file
26
mobile-scrollbar/src/main.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
const tabButtons = document.querySelectorAll('.tabs__item');
|
||||||
|
// Leave only necessary sections id
|
||||||
|
const sectionIds = [
|
||||||
|
'projector_longdescription',
|
||||||
|
'projector_dictionary',
|
||||||
|
'projector_enclosures',
|
||||||
|
'projector_warranty',
|
||||||
|
'product_questions_list',
|
||||||
|
'opinions_section',
|
||||||
|
'projector_blog',
|
||||||
|
'products_associated_zone1'
|
||||||
|
];
|
||||||
|
|
||||||
|
const tabContents = sectionIds.map(id => document.getElementById(id));
|
||||||
|
|
||||||
|
tabButtons.forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
tabButtons.forEach(b => b?.classList.remove('idm-active'));
|
||||||
|
btn?.classList.add('idm-active');
|
||||||
|
|
||||||
|
tabContents.forEach(content => content?.classList.remove('idm-active'));
|
||||||
|
const tabId = btn?.dataset.tab;
|
||||||
|
|
||||||
|
document.getElementById(tabId)?.classList.add('idm-active');
|
||||||
|
});
|
||||||
|
});
|
||||||
112
mobile-scrollbar/src/style.less
Normal file
112
mobile-scrollbar/src/style.less
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
@keyframes slide-in {
|
||||||
|
from {
|
||||||
|
transform: scaleX(0);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in-opacity {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
border-bottom: 3px solid #efefef;
|
||||||
|
|
||||||
|
@media(max-width: 978px) {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
height: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: #efefef;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background-color: black;
|
||||||
|
min-width: 30%;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: #2e8b57;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(max-width: 978px) {
|
||||||
|
overflow-y: hidden;
|
||||||
|
overflow-x: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
white-space: nowrap;
|
||||||
|
position: relative;
|
||||||
|
padding: 8px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color .3s ease;
|
||||||
|
color: #888;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.idm-active {
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -3px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 2.5px;
|
||||||
|
background-color: black;
|
||||||
|
border-radius: 2px;
|
||||||
|
animation: slide-in .3s ease;
|
||||||
|
@media(max-width: 978px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leave only necessary sections id
|
||||||
|
#projector_longdescription,
|
||||||
|
#projector_dictionary,
|
||||||
|
#projector_enclosures,
|
||||||
|
#projector_warranty,
|
||||||
|
#product_questions_list,
|
||||||
|
#opinions_section,
|
||||||
|
#projector_blog,
|
||||||
|
#products_associated_zone1 {
|
||||||
|
display: none;
|
||||||
|
animation: slide-in-opacity .3s ease;
|
||||||
|
padding-top: 5rem;
|
||||||
|
&.idm-active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
66
mobile-tabs /index.xslt
Normal file
66
mobile-tabs /index.xslt
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?><iai:component><iai:componentsdata><cdata-start/>
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="tabs__container">
|
||||||
|
|
||||||
|
<!--Opis-->
|
||||||
|
<iaixsl:if test="page/projector/product/vlongdescription and not(page/projector/product/vlongdescription = '')">
|
||||||
|
<div class="tabs__item idm-active" data-tab="projector_longdescription">
|
||||||
|
<iai:variable vid="Opis produktu" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Parametry-->
|
||||||
|
<iaixsl:if
|
||||||
|
test="/shop/page/projector/product/price/@srp or (count(/shop/page/projector/product/dictionary/items) > 0) or ($product_producer_label and not(/shop/page/projector/product/firm/@name = '')) or ($product_code_label and /shop/page/projector/product/@code) or ($product_series_label and /shop/page/projector/product/series) or ($product_producer_code_label and count(/shop/page/projector/product/sizes/size[@code_producer and not(@code_producer = '')]) > 0) or (count(/shop/page/projector/product/responsible_entity/producer | /shop/page/projector/product/responsible_entity/persons/person) > 0)"
|
||||||
|
>
|
||||||
|
<div class="tabs__item" data-tab="projector_dictionary">
|
||||||
|
<iai:variable vid="Parametry techniczne" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Do pobrania-->
|
||||||
|
<iaixsl:if
|
||||||
|
test="(/shop/page/projector/product/enclosures/documents/item) or (/shop/page/projector/product/enclosures/audio/item) or (/shop/page/projector/product/enclosures/other) or (/shop/page/projector/product/enclosures/images_attachments/item) or (/shop/page/projector/product/enclosures/video/item)"
|
||||||
|
>
|
||||||
|
<div class="tabs__item" data-tab="projector_enclosures">
|
||||||
|
<iai:variable vid="Do pobrania" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Gwarancja-->
|
||||||
|
<iaixsl:if test="page/projector/product/warranty and not(page/projector/product/warranty= '')">
|
||||||
|
<div class="tabs__item" data-tab="projector_warranty">
|
||||||
|
<iai:variable vid="Gwarancja" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Pytania-->
|
||||||
|
<iaixsl:if test="page/projector/product/warranty and not(page/projector/product/warranty= '')">
|
||||||
|
<div class="tabs__item" data-tab="product_questions_list">
|
||||||
|
<iai:variable vid="Pytania" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Opinie-->
|
||||||
|
<div class="tabs__item" data-tab="opinions_section">
|
||||||
|
<iai:variable vid="Opinie" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--Blog-->
|
||||||
|
<iaixsl:if test="count(/shop/page/projector/blog_entries/item) > 0">
|
||||||
|
<div class="tabs__item" data-tab="projector_blog">
|
||||||
|
<iai:variable vid="Blog" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
<!--Rekomendacje 1-->
|
||||||
|
<iaixsl:if test="page/projector/products_associated_zone1">
|
||||||
|
<div class="tabs__item" data-tab="products_associated_zone1">
|
||||||
|
<iai:variable vid="Rekomendacje 1" />
|
||||||
|
</div>
|
||||||
|
</iaixsl:if>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<cdata-end/></iai:componentsdata></iai:component>
|
||||||
106
mobile-tabs /src/main.js
Normal file
106
mobile-tabs /src/main.js
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
// Leave only necessary sections id
|
||||||
|
const sectionIds = [
|
||||||
|
'projector_longdescription',
|
||||||
|
'projector_dictionary',
|
||||||
|
'projector_enclosures',
|
||||||
|
'projector_warranty',
|
||||||
|
'product_questions_list',
|
||||||
|
'opinions_section',
|
||||||
|
'projector_blog',
|
||||||
|
'products_associated_zone1'
|
||||||
|
];
|
||||||
|
const tabContents = sectionIds.map(id => document.getElementById(id));
|
||||||
|
const tabButtons = document.querySelectorAll('.tabs__item');
|
||||||
|
let isMobileView = false;
|
||||||
|
|
||||||
|
// Engine
|
||||||
|
(() => {
|
||||||
|
let resizeTimeout
|
||||||
|
let prevView = app_shop.vars.view
|
||||||
|
const container = document.querySelector('#container')
|
||||||
|
|
||||||
|
const VIEW_PHONE = [1, 2]
|
||||||
|
const VIEW_TABLET_DESKTOP = [3, 4]
|
||||||
|
|
||||||
|
const handleResize = () => {
|
||||||
|
if (!container?.classList.contains('projector_page')) return
|
||||||
|
|
||||||
|
clearTimeout(resizeTimeout)
|
||||||
|
resizeTimeout = setTimeout(() => {
|
||||||
|
const currentView = app_shop.vars.view
|
||||||
|
|
||||||
|
if (VIEW_PHONE.includes(currentView)) {
|
||||||
|
isMobileView = true
|
||||||
|
placeContentsInBetween()
|
||||||
|
} else if (VIEW_TABLET_DESKTOP.includes(currentView)) {
|
||||||
|
isMobileView = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VIEW_TABLET_DESKTOP.includes(prevView) && VIEW_PHONE.includes(currentView)) {
|
||||||
|
placeContentsInBetween()
|
||||||
|
} else if (VIEW_PHONE.includes(prevView) && VIEW_TABLET_DESKTOP.includes(currentView)) {
|
||||||
|
placeContentsDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
prevView = currentView
|
||||||
|
|
||||||
|
initTabs()
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
handleResize()
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize)
|
||||||
|
})()
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
function handleTabClick(e) {
|
||||||
|
const btn = e.currentTarget
|
||||||
|
|
||||||
|
if (isMobileView) {
|
||||||
|
tabButtons.forEach(b => {
|
||||||
|
if (b !== btn) b?.classList.remove('idm-active')
|
||||||
|
})
|
||||||
|
btn?.classList.toggle('idm-active')
|
||||||
|
} else {
|
||||||
|
tabButtons.forEach(b => b?.classList.remove('idm-active'))
|
||||||
|
btn?.classList.add('idm-active')
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabId = btn?.dataset.tab
|
||||||
|
if (isMobileView) {
|
||||||
|
tabContents.forEach(content => {
|
||||||
|
if(content.id !== tabId) content?.classList.remove('idm-active')
|
||||||
|
})
|
||||||
|
document.getElementById(tabId)?.classList.toggle('idm-active')
|
||||||
|
} else {
|
||||||
|
tabContents.forEach(content => content?.classList.remove('idm-active'))
|
||||||
|
document.getElementById(tabId)?.classList.add('idm-active')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initTabs() {
|
||||||
|
tabButtons.forEach(btn => {
|
||||||
|
btn.removeEventListener('click', handleTabClick)
|
||||||
|
btn.addEventListener('click', handleTabClick)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function placeContentsInBetween() {
|
||||||
|
tabButtons.forEach(btn => {
|
||||||
|
const tabId = btn?.dataset.tab
|
||||||
|
const relevantTab = document.getElementById(tabId)
|
||||||
|
btn.insertAdjacentElement('afterend', relevantTab)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function placeContentsDefault() {
|
||||||
|
const tabs = document.querySelector('.tabs')
|
||||||
|
tabButtons.forEach(btn => {
|
||||||
|
const tabId = btn?.dataset.tab
|
||||||
|
const relevantTab = document.getElementById(tabId)
|
||||||
|
tabs.insertAdjacentElement('afterend', relevantTab)
|
||||||
|
})
|
||||||
|
}
|
||||||
113
mobile-tabs /src/style.less
Normal file
113
mobile-tabs /src/style.less
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
@keyframes slide-in-opacity {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
border-bottom: 3px solid #efefef;
|
||||||
|
|
||||||
|
@media (max-width: 978px) {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
@media (max-width: 978px) {
|
||||||
|
gap: 2rem;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
white-space: nowrap;
|
||||||
|
position: relative;
|
||||||
|
padding: 8px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color .3s ease;
|
||||||
|
color: #888;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.idm-active {
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 978px) {
|
||||||
|
&::before {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 978px) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after, &::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -3px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 2.5px;
|
||||||
|
background-color: black;
|
||||||
|
border-radius: 2px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mobile plus&minus
|
||||||
|
@media (max-width: 978px) {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&::after, &::before {
|
||||||
|
opacity: 1;
|
||||||
|
width: 2rem;
|
||||||
|
left: calc(100% - 2rem);
|
||||||
|
bottom: 50%;
|
||||||
|
transform: translateY(50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
opacity: 1;
|
||||||
|
transform: rotate(90deg) translateY(0) translateX(5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leave only necessary sections id
|
||||||
|
#projector_longdescription,
|
||||||
|
#projector_dictionary,
|
||||||
|
#projector_enclosures,
|
||||||
|
#projector_warranty,
|
||||||
|
#product_questions_list,
|
||||||
|
#opinions_section,
|
||||||
|
#projector_blog,
|
||||||
|
#products_associated_zone1 {
|
||||||
|
display: none;
|
||||||
|
animation: slide-in-opacity .3s ease;
|
||||||
|
padding-top: 5rem;
|
||||||
|
|
||||||
|
&.idm-active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user