create-template-html-css 1.4.3 â 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +92 -0
- package/INSERT-QUICK-REFERENCE.md +147 -0
- package/README.md +33 -2
- package/RELEASE-NOTES-v1.6.1.md +129 -0
- package/RELEASE-STATUS.md +203 -0
- package/RELEASE-v1.6.2.md +169 -0
- package/SECURITY-AUDIT.md +157 -0
- package/TEST-REPORT.md +110 -0
- package/VERIFICATION-REPORT.md +162 -0
- package/bin/cli.js +416 -247
- package/demo/css/accordion-component.css +135 -0
- package/demo/css/button-component.css +110 -0
- package/demo/css/card-component.css +381 -0
- package/demo/index.html +169 -0
- package/demo/js/accordion-component.js +31 -0
- package/demo/js/button-component.js +17 -0
- package/demo/js/card-component.js +124 -0
- package/package.json +6 -3
- package/src/generator.js +165 -64
- package/src/index.js +1 -1
- package/src/inserter.js +352 -146
- package/templates/accordion/index.html +67 -0
- package/templates/accordion/script.js +29 -0
- package/templates/accordion/style.css +133 -0
- package/templates/counter/index.html +46 -0
- package/templates/counter/script.js +88 -0
- package/templates/counter/style.css +164 -0
- package/templates/tabs/index.html +83 -0
- package/templates/tabs/script.js +46 -0
- package/templates/tabs/style.css +173 -0
- package/templates/todo-list/index.html +45 -0
- package/templates/todo-list/script.js +69 -0
- package/templates/todo-list/style.css +138 -0
- package/v1.6.2-IMPROVEMENTS.md +185 -0
- package/CONTRIBUTING.md +0 -62
- package/INSERT-DEMO.md +0 -171
- package/QUICKSTART.md +0 -195
- package/SECURITY.md +0 -95
- package/SHOWCASE.html +0 -342
- package/test-insert.html +0 -54
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
* {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
body {
|
|
8
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
9
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
10
|
+
min-height: 100vh;
|
|
11
|
+
display: flex;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
align-items: center;
|
|
14
|
+
padding: 20px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.container {
|
|
18
|
+
width: 100%;
|
|
19
|
+
max-width: 600px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.accordion-wrapper {
|
|
23
|
+
background: white;
|
|
24
|
+
border-radius: 12px;
|
|
25
|
+
padding: 40px;
|
|
26
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.accordion-wrapper h1 {
|
|
30
|
+
color: #333;
|
|
31
|
+
margin-bottom: 30px;
|
|
32
|
+
text-align: center;
|
|
33
|
+
font-size: 28px;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.accordion {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
gap: 12px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.accordion-item {
|
|
43
|
+
border: 2px solid #e0e0e0;
|
|
44
|
+
border-radius: 8px;
|
|
45
|
+
overflow: hidden;
|
|
46
|
+
transition: all 0.3s;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.accordion-item.active {
|
|
50
|
+
border-color: #667eea;
|
|
51
|
+
background: #f8f9ff;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.accordion-header {
|
|
55
|
+
width: 100%;
|
|
56
|
+
padding: 20px;
|
|
57
|
+
background: white;
|
|
58
|
+
border: none;
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
display: flex;
|
|
61
|
+
justify-content: space-between;
|
|
62
|
+
align-items: center;
|
|
63
|
+
font-size: 16px;
|
|
64
|
+
font-weight: 600;
|
|
65
|
+
color: #333;
|
|
66
|
+
transition: all 0.3s;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.accordion-item.active .accordion-header {
|
|
70
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
71
|
+
color: white;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.accordion-header:hover {
|
|
75
|
+
background: #f5f5f5;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.accordion-item.active .accordion-header:hover {
|
|
79
|
+
background: linear-gradient(135deg, #5568d3 0%, #6a3f99 100%);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.accordion-header .icon {
|
|
83
|
+
display: inline-flex;
|
|
84
|
+
align-items: center;
|
|
85
|
+
justify-content: center;
|
|
86
|
+
width: 24px;
|
|
87
|
+
height: 24px;
|
|
88
|
+
font-size: 18px;
|
|
89
|
+
font-weight: bold;
|
|
90
|
+
transition: transform 0.3s;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.accordion-item.active .accordion-header .icon {
|
|
94
|
+
transform: rotate(45deg);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.accordion-content {
|
|
98
|
+
max-height: 0;
|
|
99
|
+
overflow: hidden;
|
|
100
|
+
transition: max-height 0.3s ease;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.accordion-item.active .accordion-content {
|
|
104
|
+
max-height: 500px;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.accordion-body {
|
|
108
|
+
padding: 20px;
|
|
109
|
+
color: #666;
|
|
110
|
+
line-height: 1.6;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* Responsive */
|
|
114
|
+
@media (max-width: 600px) {
|
|
115
|
+
.accordion-wrapper {
|
|
116
|
+
padding: 20px;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.accordion-wrapper h1 {
|
|
120
|
+
font-size: 22px;
|
|
121
|
+
margin-bottom: 20px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.accordion-header {
|
|
125
|
+
padding: 15px;
|
|
126
|
+
font-size: 14px;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.accordion-body {
|
|
130
|
+
padding: 15px;
|
|
131
|
+
font-size: 14px;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{{name}} - Counter App</title>
|
|
7
|
+
<link rel="stylesheet" href="style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="container">
|
|
11
|
+
<div class="counter-card">
|
|
12
|
+
<h1>Counter</h1>
|
|
13
|
+
|
|
14
|
+
<div class="counter-display">
|
|
15
|
+
<span id="counterValue">0</span>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="button-group">
|
|
19
|
+
<button id="decrementBtn" class="btn btn-danger">â</button>
|
|
20
|
+
<button id="resetBtn" class="btn btn-secondary">Reset</button>
|
|
21
|
+
<button id="incrementBtn" class="btn btn-success">+</button>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="stats">
|
|
25
|
+
<div class="stat-item">
|
|
26
|
+
<label>Step Size:</label>
|
|
27
|
+
<select id="stepSize" class="step-select">
|
|
28
|
+
<option value="1">1</option>
|
|
29
|
+
<option value="5">5</option>
|
|
30
|
+
<option value="10">10</option>
|
|
31
|
+
<option value="100">100</option>
|
|
32
|
+
</select>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="history">
|
|
37
|
+
<h3>History</h3>
|
|
38
|
+
<div id="historyList" class="history-list">
|
|
39
|
+
<p class="empty">No changes yet</p>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
<script src="script.js"></script>
|
|
45
|
+
</body>
|
|
46
|
+
</html>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Counter Application with History
|
|
2
|
+
|
|
3
|
+
let counter = 0;
|
|
4
|
+
const counterValue = document.getElementById('counterValue');
|
|
5
|
+
const incrementBtn = document.getElementById('incrementBtn');
|
|
6
|
+
const decrementBtn = document.getElementById('decrementBtn');
|
|
7
|
+
const resetBtn = document.getElementById('resetBtn');
|
|
8
|
+
const stepSelect = document.getElementById('stepSize');
|
|
9
|
+
const historyList = document.getElementById('historyList');
|
|
10
|
+
|
|
11
|
+
// Get step size
|
|
12
|
+
function getStepSize() {
|
|
13
|
+
return parseInt(stepSelect.value);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Update display
|
|
17
|
+
function updateDisplay() {
|
|
18
|
+
counterValue.textContent = counter;
|
|
19
|
+
|
|
20
|
+
// Change color based on value
|
|
21
|
+
const display = counterValue.parentElement;
|
|
22
|
+
if (counter > 0) {
|
|
23
|
+
display.style.background = 'linear-gradient(135deg, #10b981 0%, #059669 100%)';
|
|
24
|
+
} else if (counter < 0) {
|
|
25
|
+
display.style.background = 'linear-gradient(135deg, #ef4444 0%, #dc2626 100%)';
|
|
26
|
+
} else {
|
|
27
|
+
display.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Add to history
|
|
32
|
+
function addToHistory(action, value) {
|
|
33
|
+
const now = new Date().toLocaleTimeString();
|
|
34
|
+
const item = document.createElement('div');
|
|
35
|
+
item.className = 'history-item';
|
|
36
|
+
item.textContent = `${now} - ${action} (${value > 0 ? '+' : ''}${value})`;
|
|
37
|
+
|
|
38
|
+
// Remove empty message if exists
|
|
39
|
+
if (historyList.querySelector('.empty')) {
|
|
40
|
+
historyList.innerHTML = '';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
historyList.insertBefore(item, historyList.firstChild);
|
|
44
|
+
|
|
45
|
+
// Keep only last 10 items
|
|
46
|
+
while (historyList.children.length > 10) {
|
|
47
|
+
historyList.removeChild(historyList.lastChild);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Increment
|
|
52
|
+
function increment() {
|
|
53
|
+
const step = getStepSize();
|
|
54
|
+
counter += step;
|
|
55
|
+
updateDisplay();
|
|
56
|
+
addToHistory('Increment', step);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Decrement
|
|
60
|
+
function decrement() {
|
|
61
|
+
const step = getStepSize();
|
|
62
|
+
counter -= step;
|
|
63
|
+
updateDisplay();
|
|
64
|
+
addToHistory('Decrement', -step);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Reset
|
|
68
|
+
function reset() {
|
|
69
|
+
const oldValue = counter;
|
|
70
|
+
counter = 0;
|
|
71
|
+
updateDisplay();
|
|
72
|
+
addToHistory('Reset', -oldValue);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Event listeners
|
|
76
|
+
incrementBtn.addEventListener('click', increment);
|
|
77
|
+
decrementBtn.addEventListener('click', decrement);
|
|
78
|
+
resetBtn.addEventListener('click', reset);
|
|
79
|
+
|
|
80
|
+
// Keyboard support
|
|
81
|
+
document.addEventListener('keydown', (e) => {
|
|
82
|
+
if (e.key === 'ArrowUp' || e.key === '+') increment();
|
|
83
|
+
if (e.key === 'ArrowDown' || e.key === '-') decrement();
|
|
84
|
+
if (e.key === '0' || e.key === 'r') reset();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Initialize
|
|
88
|
+
updateDisplay();
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
* {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
body {
|
|
8
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
9
|
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
10
|
+
min-height: 100vh;
|
|
11
|
+
display: flex;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
align-items: center;
|
|
14
|
+
padding: 20px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.container {
|
|
18
|
+
width: 100%;
|
|
19
|
+
max-width: 400px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.counter-card {
|
|
23
|
+
background: white;
|
|
24
|
+
border-radius: 16px;
|
|
25
|
+
padding: 40px 30px;
|
|
26
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.counter-card h1 {
|
|
30
|
+
text-align: center;
|
|
31
|
+
color: #333;
|
|
32
|
+
margin-bottom: 30px;
|
|
33
|
+
font-size: 28px;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.counter-display {
|
|
37
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
38
|
+
color: white;
|
|
39
|
+
border-radius: 12px;
|
|
40
|
+
padding: 40px;
|
|
41
|
+
text-align: center;
|
|
42
|
+
margin-bottom: 30px;
|
|
43
|
+
font-size: 64px;
|
|
44
|
+
font-weight: bold;
|
|
45
|
+
min-height: 140px;
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.button-group {
|
|
53
|
+
display: flex;
|
|
54
|
+
gap: 12px;
|
|
55
|
+
margin-bottom: 25px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.btn {
|
|
59
|
+
flex: 1;
|
|
60
|
+
padding: 15px;
|
|
61
|
+
border: none;
|
|
62
|
+
border-radius: 8px;
|
|
63
|
+
font-size: 18px;
|
|
64
|
+
font-weight: 600;
|
|
65
|
+
cursor: pointer;
|
|
66
|
+
transition: all 0.3s;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.btn-success {
|
|
70
|
+
background: #10b981;
|
|
71
|
+
color: white;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.btn-success:hover {
|
|
75
|
+
background: #059669;
|
|
76
|
+
transform: translateY(-2px);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.btn-danger {
|
|
80
|
+
background: #ef4444;
|
|
81
|
+
color: white;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.btn-danger:hover {
|
|
85
|
+
background: #dc2626;
|
|
86
|
+
transform: translateY(-2px);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.btn-secondary {
|
|
90
|
+
background: #6b7280;
|
|
91
|
+
color: white;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.btn-secondary:hover {
|
|
95
|
+
background: #4b5563;
|
|
96
|
+
transform: translateY(-2px);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.stats {
|
|
100
|
+
background: #f3f4f6;
|
|
101
|
+
border-radius: 8px;
|
|
102
|
+
padding: 15px;
|
|
103
|
+
margin-bottom: 20px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.stat-item {
|
|
107
|
+
display: flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
justify-content: space-between;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.stat-item label {
|
|
113
|
+
color: #666;
|
|
114
|
+
font-weight: 600;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.step-select {
|
|
118
|
+
padding: 8px 12px;
|
|
119
|
+
border: 2px solid #e5e7eb;
|
|
120
|
+
border-radius: 6px;
|
|
121
|
+
font-size: 14px;
|
|
122
|
+
cursor: pointer;
|
|
123
|
+
background: white;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.step-select:focus {
|
|
127
|
+
outline: none;
|
|
128
|
+
border-color: #667eea;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.history {
|
|
132
|
+
border-top: 2px solid #e5e7eb;
|
|
133
|
+
padding-top: 20px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.history h3 {
|
|
137
|
+
color: #333;
|
|
138
|
+
margin-bottom: 12px;
|
|
139
|
+
font-size: 14px;
|
|
140
|
+
text-transform: uppercase;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.history-list {
|
|
144
|
+
max-height: 120px;
|
|
145
|
+
overflow-y: auto;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.history-item {
|
|
149
|
+
padding: 8px;
|
|
150
|
+
background: #f9fafb;
|
|
151
|
+
border-radius: 6px;
|
|
152
|
+
font-size: 13px;
|
|
153
|
+
color: #666;
|
|
154
|
+
margin-bottom: 8px;
|
|
155
|
+
border-left: 3px solid #667eea;
|
|
156
|
+
padding-left: 12px;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.empty {
|
|
160
|
+
text-align: center;
|
|
161
|
+
color: #999;
|
|
162
|
+
font-size: 13px;
|
|
163
|
+
padding: 15px;
|
|
164
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{{name}} - Tabs Component</title>
|
|
7
|
+
<link rel="stylesheet" href="style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="container">
|
|
11
|
+
<div class="tabs-wrapper">
|
|
12
|
+
<h1>Tabbed Content</h1>
|
|
13
|
+
|
|
14
|
+
<div class="tabs">
|
|
15
|
+
<div class="tab-buttons">
|
|
16
|
+
<button class="tab-button active" data-tab="tab1">
|
|
17
|
+
<span class="icon">đ</span> Overview
|
|
18
|
+
</button>
|
|
19
|
+
<button class="tab-button" data-tab="tab2">
|
|
20
|
+
<span class="icon">âī¸</span> Features
|
|
21
|
+
</button>
|
|
22
|
+
<button class="tab-button" data-tab="tab3">
|
|
23
|
+
<span class="icon">đŦ</span> Reviews
|
|
24
|
+
</button>
|
|
25
|
+
<button class="tab-button" data-tab="tab4">
|
|
26
|
+
<span class="icon">âšī¸</span> About
|
|
27
|
+
</button>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="tab-contents">
|
|
31
|
+
<div class="tab-content active" id="tab1">
|
|
32
|
+
<h2>Overview</h2>
|
|
33
|
+
<p>This is a fully functional tabs component that uses DOM manipulation to switch between different content sections. Click on the tab buttons above to switch content.</p>
|
|
34
|
+
<ul>
|
|
35
|
+
<li>Easy to implement</li>
|
|
36
|
+
<li>Responsive design</li>
|
|
37
|
+
<li>Smooth transitions</li>
|
|
38
|
+
<li>Clean and modern styling</li>
|
|
39
|
+
</ul>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="tab-content" id="tab2">
|
|
43
|
+
<h2>Features</h2>
|
|
44
|
+
<p>Our tabs component comes with many great features:</p>
|
|
45
|
+
<ul>
|
|
46
|
+
<li>đ¨ Customizable colors and styles</li>
|
|
47
|
+
<li>đą Mobile responsive layout</li>
|
|
48
|
+
<li>â¨ī¸ Keyboard navigation support</li>
|
|
49
|
+
<li>âŋ Accessible to screen readers</li>
|
|
50
|
+
<li>⥠Fast and smooth animations</li>
|
|
51
|
+
<li>đ§ Easy to customize and extend</li>
|
|
52
|
+
</ul>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<div class="tab-content" id="tab3">
|
|
56
|
+
<h2>Reviews</h2>
|
|
57
|
+
<div class="review">
|
|
58
|
+
<p><strong>âââââ</strong> Perfect component!</p>
|
|
59
|
+
<p>"This tabs component is exactly what I needed for my project. Easy to use and looks great!"</p>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="review">
|
|
62
|
+
<p><strong>âââââ</strong> Highly recommended</p>
|
|
63
|
+
<p>"Great functionality and clean code. Highly recommend to anyone building web applications."</p>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="tab-content" id="tab4">
|
|
68
|
+
<h2>About</h2>
|
|
69
|
+
<p>This tabs component was created to demonstrate DOM manipulation techniques in JavaScript. It shows how to:</p>
|
|
70
|
+
<ul>
|
|
71
|
+
<li>Select DOM elements</li>
|
|
72
|
+
<li>Add/remove CSS classes</li>
|
|
73
|
+
<li>Handle events dynamically</li>
|
|
74
|
+
<li>Create interactive user interfaces</li>
|
|
75
|
+
</ul>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
<script src="script.js"></script>
|
|
82
|
+
</body>
|
|
83
|
+
</html>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Tabs Component
|
|
2
|
+
|
|
3
|
+
const tabButtons = document.querySelectorAll('.tab-button');
|
|
4
|
+
const tabContents = document.querySelectorAll('.tab-content');
|
|
5
|
+
|
|
6
|
+
// Switch tab
|
|
7
|
+
function switchTab(e) {
|
|
8
|
+
const button = e.currentTarget;
|
|
9
|
+
const tabId = button.getAttribute('data-tab');
|
|
10
|
+
|
|
11
|
+
// Remove active class from all buttons
|
|
12
|
+
tabButtons.forEach(btn => btn.classList.remove('active'));
|
|
13
|
+
|
|
14
|
+
// Add active class to clicked button
|
|
15
|
+
button.classList.add('active');
|
|
16
|
+
|
|
17
|
+
// Hide all content
|
|
18
|
+
tabContents.forEach(content => content.classList.remove('active'));
|
|
19
|
+
|
|
20
|
+
// Show selected content
|
|
21
|
+
const selectedContent = document.getElementById(tabId);
|
|
22
|
+
if (selectedContent) {
|
|
23
|
+
selectedContent.classList.add('active');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Add event listeners
|
|
28
|
+
tabButtons.forEach(button => {
|
|
29
|
+
button.addEventListener('click', switchTab);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Keyboard navigation
|
|
33
|
+
document.addEventListener('keydown', (e) => {
|
|
34
|
+
const activeButton = document.querySelector('.tab-button.active');
|
|
35
|
+
const activeIndex = Array.from(tabButtons).indexOf(activeButton);
|
|
36
|
+
|
|
37
|
+
if (e.key === 'ArrowRight') {
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
const nextIndex = (activeIndex + 1) % tabButtons.length;
|
|
40
|
+
tabButtons[nextIndex].click();
|
|
41
|
+
} else if (e.key === 'ArrowLeft') {
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
const prevIndex = (activeIndex - 1 + tabButtons.length) % tabButtons.length;
|
|
44
|
+
tabButtons[prevIndex].click();
|
|
45
|
+
}
|
|
46
|
+
});
|