File size: 4,696 Bytes
0a96199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Animated Tabs JavaScript - Blinkist Style
class AnimatedTabs {
    constructor(container) {
        this.container = container;
        this.tabButtons = container.querySelectorAll('.tab-button');
        this.tabPanels = container.querySelectorAll('.tab-panel');
        this.tabSlider = container.querySelector('.tab-slider');
        this.isAnimating = false;
        
        this.init();
    }
    
    init() {
        this.setInitialState();
        this.bindEvents();
        this.addResponsiveBehavior();
    }
    
    setInitialState() {
        // Set initial slider position
        const activeButton = this.container.querySelector('.tab-button.active');
        if (activeButton && this.tabSlider) {
            this.updateSliderPosition(activeButton);
        }
        
        // Ensure first tab is active if none are
        if (!activeButton && this.tabButtons.length > 0) {
            this.tabButtons[0].classList.add('active');
            this.tabPanels[0].classList.add('active');
            this.updateSliderPosition(this.tabButtons[0]);
        }
    }
    
    bindEvents() {
        this.tabButtons.forEach(button => {
            button.addEventListener('click', (e) => {
                e.preventDefault();
                this.switchTab(button);
            });
        });
    }
    
    switchTab(activeButton) {
        if (this.isAnimating) return;
        
        this.isAnimating = true;
        const targetTab = activeButton.getAttribute('data-tab');
        
        // Remove active class from all buttons and panels
        this.tabButtons.forEach(btn => btn.classList.remove('active'));
        this.tabPanels.forEach(panel => panel.classList.remove('active'));
        
        // Add active class to clicked button and target panel
        activeButton.classList.add('active');
        const targetPanel = this.container.querySelector(`#${targetTab}`);
        if (targetPanel) {
            targetPanel.classList.add('active');
        }
        
        // Animate slider
        this.updateSliderPosition(activeButton);
        
        // Trigger custom event
        this.container.dispatchEvent(new CustomEvent('tabChanged', {
            detail: {
                activeTab: targetTab,
                activeButton: activeButton,
                activePanel: targetPanel
            }
        }));
        
        // Reset animation flag after transition
        setTimeout(() => {
            this.isAnimating = false;
        }, 400);
    }
    
    updateSliderPosition(button) {
        if (!this.tabSlider) return;
        
        const buttonRect = button.getBoundingClientRect();
        const containerRect = this.container.getBoundingClientRect();
        
        this.tabSlider.style.width = button.offsetWidth + 'px';
        this.tabSlider.style.left = (button.offsetLeft - this.container.offsetLeft) + 'px';
    }
    
    addResponsiveBehavior() {
        // Handle window resize
        let resizeTimeout;
        window.addEventListener('resize', () => {
            clearTimeout(resizeTimeout);
            resizeTimeout = setTimeout(() => {
                const activeButton = this.container.querySelector('.tab-button.active');
                if (activeButton) {
                    this.updateSliderPosition(activeButton);
                }
            }, 100);
        });
        
        // Add hover effects for mobile
        if (window.innerWidth <= 768) {
            this.tabButtons.forEach(button => {
                button.addEventListener('mouseenter', () => {
                    if (!button.classList.contains('active')) {
                        button.style.transform = 'scale(1.05)';
                    }
                });
                
                button.addEventListener('mouseleave', () => {
                    button.style.transform = 'scale(1)';
                });
            });
        }
    }
    
    // Public methods
    switchToTab(tabId) {
        const button = this.container.querySelector(`[data-tab="${tabId}"]`);
        if (button) {
            this.switchTab(button);
        }
    }
    
    getActiveTab() {
        const activeButton = this.container.querySelector('.tab-button.active');
        return activeButton ? activeButton.getAttribute('data-tab') : null;
    }
}

// Auto-initialize tabs when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
    const tabsContainers = document.querySelectorAll('.tabs-wrapper');
    tabsContainers.forEach(container => {
        new AnimatedTabs(container);
    });
});

// Export for module usage
if (typeof module !== 'undefined' && module.exports) {
    module.exports = AnimatedTabs;
}