New
This commit is contained in:
80
frontend/js/components/slidingTabs.js
Normal file
80
frontend/js/components/slidingTabs.js
Normal file
@@ -0,0 +1,80 @@
|
||||
export default class SlidingTabs {
|
||||
/**
|
||||
* @param {HTMLElement} containerElement - The main container element with the `data-sliding-tabs-container` attribute.
|
||||
*/
|
||||
constructor(containerElement) {
|
||||
this.container = containerElement;
|
||||
this.indicator = this.container.querySelector('[data-tab-indicator]');
|
||||
this.tabs = this.container.querySelectorAll('[data-tab-item]');
|
||||
|
||||
// Find the initially active tab and store it as the component's state
|
||||
this.activeTab = this.container.querySelector('.tab-active');
|
||||
|
||||
if (!this.indicator || this.tabs.length === 0) {
|
||||
console.error('SlidingTabs component is missing required elements (indicator or items).', this.container);
|
||||
return;
|
||||
}
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
// Set initial indicator position
|
||||
if (this.activeTab) {
|
||||
// Use a small delay to ensure layout is fully calculated
|
||||
setTimeout(() => this.updateIndicator(this.activeTab), 50);
|
||||
}
|
||||
|
||||
// Bind all necessary event listeners
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
updateIndicator(targetTab) {
|
||||
if (!targetTab) return;
|
||||
|
||||
const containerRect = this.container.getBoundingClientRect();
|
||||
const targetRect = targetTab.getBoundingClientRect();
|
||||
|
||||
const left = targetRect.left - containerRect.left;
|
||||
const width = targetRect.width;
|
||||
|
||||
this.indicator.style.left = `${left}px`;
|
||||
this.indicator.style.width = `${width}px`;
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.tabs.forEach(tab => {
|
||||
// On click, update the active state
|
||||
tab.addEventListener('click', (e) => {
|
||||
// e.preventDefault(); // Uncomment if using <a> tags for SPA routing
|
||||
|
||||
if (this.activeTab) {
|
||||
this.activeTab.classList.remove('tab-active');
|
||||
}
|
||||
|
||||
tab.classList.add('tab-active');
|
||||
this.activeTab = tab; // Update the component's state
|
||||
this.updateIndicator(this.activeTab);
|
||||
});
|
||||
|
||||
// On hover, preview the indicator position
|
||||
tab.addEventListener('mouseenter', () => {
|
||||
this.updateIndicator(tab);
|
||||
});
|
||||
});
|
||||
|
||||
// When the mouse leaves the entire container, reset indicator to the active tab
|
||||
this.container.addEventListener('mouseleave', () => {
|
||||
this.updateIndicator(this.activeTab);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Auto-Initialization Logic ----
|
||||
// This is the "bootstrapper". It finds all components on the page and brings them to life.
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const allTabContainers = document.querySelectorAll('[data-sliding-tabs-container]');
|
||||
allTabContainers.forEach(container => {
|
||||
new SlidingTabs(container);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user