create-template-html-css 1.4.2 → 1.5.0

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 CHANGED
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.5.0] - 2026-01-31
9
+
10
+ ### Added
11
+ - **4 New DOM Manipulation Templates**:
12
+ - **Todo List**: Interactive task management with add/remove items, checkboxes for completion status, and real-time statistics
13
+ - **Counter**: Increment/decrement counter with adjustable step sizes, color-changing display, and change history
14
+ - **Accordion**: Collapsible FAQ-style sections with smooth animations and toggle functionality
15
+ - **Tabs**: Multi-section content switcher with keyboard navigation (arrow keys) and fade-in animations
16
+ - All new templates include automatic `<script src="script.js"></script>` tag in generated HTML
17
+ - Enhanced component selection in CLI with new DOM Manipulation Examples category
18
+
19
+ ### Improved
20
+ - JavaScript file is now always automatically included when creating templates (no confirmation prompt)
21
+ - Better template organization in CLI with category separators
22
+ - Updated component list command to show all 23 available templates
23
+
24
+ ## [1.4.3] - 2025-01-29
25
+
26
+ ### Documentation
27
+ - Enhanced README with detailed card template variations
28
+ - Added comprehensive card features and interactions documentation
29
+ - Improved visual presentation of template capabilities
30
+
8
31
  ## [1.4.2] - 2025-01-29
9
32
 
10
33
  ### Enhanced
package/README.md CHANGED
@@ -26,10 +26,11 @@ A powerful CLI library to create HTML+CSS element templates. Generate styled UI
26
26
  - 🌈 **Stunning Gradients** - Colorful and attractive designs
27
27
  - ⚡ **Animations** - Smooth and professional effects
28
28
  - 🔧 **Customizable** - Easy to edit and modify the code
29
- - 📦 **19 Templates** - Button, Card, Form, Navigation, Modal, Footer, Hero, Slider, Table, Spinner, Animated Cards, Typing Effect, Fade Gallery, Grid Layouts, Masonry Grid, Dashboard, Flexbox Layouts
29
+ - 📦 **23 Templates** - Button, Card, Form, Navigation, Modal, Footer, Hero, Slider, Table, Spinner, Animated Cards, Typing Effect, Fade Gallery, Grid Layouts, Masonry Grid, Dashboard, Flexbox Layouts, Todo List, Counter, Accordion, Tabs
30
30
  - 🎯 **Two Modes** - Create new projects or insert into existing HTML pages
31
31
  - 🔒 **Secure** - Input validation and path protection
32
32
  - 📚 **Well Documented** - Comprehensive guides and examples
33
+ - 🎪 **DOM Manipulation Examples** - Interactive components demonstrating JavaScript DOM manipulation techniques
33
34
 
34
35
  ## 📦 Installation
35
36
 
@@ -161,21 +162,27 @@ A collection of styled button components with multiple variations:
161
162
  - Beautiful gradients
162
163
  - Click animations
163
164
 
164
- ### 2. Card
165
+ ### 2. Card
165
166
 
166
- Responsive card component for displaying content:
167
+ Responsive card component with 6 professional variations:
167
168
 
168
- **Includes:**
169
- - Image container
170
- - Title and description
171
- - Action button
172
- - Metadata section
169
+ **Variations:**
170
+ - **Modern Card** - Featured item with badge, category, rating, and date metadata
171
+ - **Premium Card** - Pricing card with feature list and gradient styling
172
+ - **Blog Card** - Content card with tags, author info, and comment counts
173
+ - **Minimal Card** - Clean, simplified design for minimal content
174
+ - **User Profile Card** - Avatar-based card with social media links
175
+ - **Interactive Card** - Action buttons for like, share, and save functionality
173
176
 
174
177
  **Features:**
178
+ - Rich metadata displays (ratings, dates, comments, authors)
179
+ - Animated action buttons with state management
180
+ - Tag-based filtering system
181
+ - Toast notifications
182
+ - Professional gradients and animations
175
183
  - Hover image zoom effect
176
184
  - Advanced shadow effects
177
- - Responsive grid layout
178
- - Flexible content
185
+ - Fully responsive grid layout
179
186
 
180
187
  ### 3. Form
181
188
 
@@ -609,9 +616,9 @@ The only requirement is to include a copy of the license and copyright notice.
609
616
 
610
617
  ## 👨‍💻 Author
611
618
 
612
- **Ben Shabbat**
619
+ **DavidChen Benshabbat**
613
620
  - GitHub: [@benshabbat](https://github.com/benshabbat)
614
- - Email: benshabbat@example.com
621
+ - Email: benshabbat27@gmail.com
615
622
 
616
623
  ## 🔗 Links
617
624
 
@@ -635,6 +642,6 @@ If you find this project helpful, please consider:
635
642
 
636
643
  ---
637
644
 
638
- Made with ❤️ by Ben Shabbat
645
+ Made with ❤️ by DavidChen Benshabbat
639
646
 
640
647
  **Happy coding! 🚀**
package/bin/cli.js CHANGED
@@ -11,7 +11,7 @@ const chalk = require('chalk');
11
11
  program
12
12
  .name('create-template')
13
13
  .description(chalk.cyan('🎨 Create HTML/CSS UI component templates in seconds'))
14
- .version('1.4.0');
14
+ .version('1.5.0');
15
15
 
16
16
  // Add intro message
17
17
  program.on('--help', () => {
@@ -57,7 +57,12 @@ program
57
57
  new inquirer.Separator(chalk.gray('─ Flexbox Layouts')),
58
58
  { name: 'Flex Layout (Flexbox Patterns)', value: 'flex-layout' },
59
59
  { name: 'Flex Cards (Equal-height cards)', value: 'flex-cards' },
60
- { name: 'Flex Dashboard (Flexbox Admin)', value: 'flex-dashboard' }
60
+ { name: 'Flex Dashboard (Flexbox Admin)', value: 'flex-dashboard' },
61
+ new inquirer.Separator(chalk.gray('─ DOM Manipulation Examples')),
62
+ { name: 'Todo List (Add/Remove Items)', value: 'todo-list' },
63
+ { name: 'Counter (Click Handlers)', value: 'counter' },
64
+ { name: 'Accordion (Toggle Content)', value: 'accordion' },
65
+ { name: 'Tabs (Switch Sections)', value: 'tabs' }
61
66
  ]
62
67
  },
63
68
  {
@@ -78,14 +83,11 @@ program
78
83
  return true;
79
84
  }
80
85
  },
81
- {
82
- type: 'confirm',
83
- name: 'includeJs',
84
- message: 'Include JavaScript file?',
85
- default: true
86
- }
87
86
  ]);
88
87
 
88
+ // Always include JavaScript file
89
+ answers.includeJs = true;
90
+
89
91
  await generateTemplate(answers);
90
92
 
91
93
  console.log('\n' + chalk.green('✓ Template created successfully!'));
@@ -155,7 +157,12 @@ program
155
157
  new inquirer.Separator(chalk.gray('─ Flexbox Layouts')),
156
158
  { name: 'Flex Layout', value: 'flex-layout' },
157
159
  { name: 'Flex Cards', value: 'flex-cards' },
158
- { name: 'Flex Dashboard', value: 'flex-dashboard' }
160
+ { name: 'Flex Dashboard', value: 'flex-dashboard' },
161
+ new inquirer.Separator(chalk.gray('─ DOM Manipulation')),
162
+ { name: 'Todo List', value: 'todo-list' },
163
+ { name: 'Counter', value: 'counter' },
164
+ { name: 'Accordion', value: 'accordion' },
165
+ { name: 'Tabs', value: 'tabs' }
159
166
  ]
160
167
  },
161
168
  {
@@ -194,7 +201,7 @@ program
194
201
  .command('list')
195
202
  .description(chalk.green('List all available templates'))
196
203
  .action(() => {
197
- console.log('\n' + chalk.blue('📦 Available Components (19 total)\n'));
204
+ console.log('\n' + chalk.blue('📦 Available Components (23 total)\n'));
198
205
 
199
206
  console.log(chalk.yellow('━ Basic Components (9)'));
200
207
  console.log(' button Styled button component');
@@ -223,6 +230,12 @@ program
223
230
  console.log(' flex-cards Equal-height card layouts');
224
231
  console.log(' flex-dashboard Complete admin dashboard (Flexbox)');
225
232
 
233
+ console.log('\n' + chalk.red('━ DOM Manipulation Examples (4)'));
234
+ console.log(' todo-list Interactive todo list with add/remove');
235
+ console.log(' counter Click counter with history tracking');
236
+ console.log(' accordion Collapsible accordion component');
237
+ console.log(' tabs Tabbed content switcher');
238
+
226
239
  console.log('\n' + chalk.gray('Usage:'));
227
240
  console.log(' create-template create Create a new component');
228
241
  console.log(' create-template insert Insert into HTML file');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-template-html-css",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "description": "CLI tool to generate HTML and CSS templates for common UI elements",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/generator.js CHANGED
@@ -2,7 +2,7 @@ const fs = require('fs').promises;
2
2
  const path = require('path');
3
3
 
4
4
  // Security: Validate component name against whitelist
5
- const VALID_COMPONENTS = ['button', 'card', 'form', 'navigation', 'modal', 'footer', 'hero', 'slider', 'table', 'spinner', 'animated-card', 'typing-effect', 'fade-gallery', 'grid-layout', 'masonry-grid', 'dashboard-grid', 'flex-layout', 'flex-cards', 'flex-dashboard'];
5
+ const VALID_COMPONENTS = ['button', 'card', 'form', 'navigation', 'modal', 'footer', 'hero', 'slider', 'table', 'spinner', 'animated-card', 'typing-effect', 'fade-gallery', 'grid-layout', 'masonry-grid', 'dashboard-grid', 'flex-layout', 'flex-cards', 'flex-dashboard', 'todo-list', 'counter', 'accordion', 'tabs'];
6
6
 
7
7
  // Security: Sanitize filename to prevent path traversal
8
8
  function sanitizeFilename(filename) {
@@ -40,8 +40,18 @@ async function generateTemplate(options) {
40
40
  const templateDir = path.join(__dirname, '..', 'templates', component);
41
41
 
42
42
  // Copy HTML file
43
- const htmlContent = await fs.readFile(path.join(templateDir, 'index.html'), 'utf-8');
44
- await fs.writeFile(path.join(outputDir, 'index.html'), htmlContent.replace(/{{name}}/g, safeName));
43
+ let htmlContent = await fs.readFile(path.join(templateDir, 'index.html'), 'utf-8');
44
+
45
+ // Replace placeholder name
46
+ htmlContent = htmlContent.replace(/{{name}}/g, safeName);
47
+
48
+ // Add script tag if JavaScript is included
49
+ if (includeJs) {
50
+ // Insert script tag before closing </body> tag
51
+ htmlContent = htmlContent.replace('</body>', ' <script src="script.js"></script>\n</body>');
52
+ }
53
+
54
+ await fs.writeFile(path.join(outputDir, 'index.html'), htmlContent);
45
55
 
46
56
  // Copy CSS file
47
57
  const cssContent = await fs.readFile(path.join(templateDir, 'style.css'), 'utf-8');
package/src/inserter.js CHANGED
@@ -2,7 +2,7 @@ const fs = require('fs').promises;
2
2
  const path = require('path');
3
3
 
4
4
  // Security: Validate component name against whitelist
5
- const VALID_COMPONENTS = ['button', 'card', 'form', 'navigation', 'modal', 'footer', 'hero', 'slider', 'table', 'spinner', 'animated-card', 'typing-effect', 'fade-gallery', 'grid-layout', 'masonry-grid', 'dashboard-grid', 'flex-layout', 'flex-cards', 'flex-dashboard'];
5
+ const VALID_COMPONENTS = ['button', 'card', 'form', 'navigation', 'modal', 'footer', 'hero', 'slider', 'table', 'spinner', 'animated-card', 'typing-effect', 'fade-gallery', 'grid-layout', 'masonry-grid', 'dashboard-grid', 'flex-layout', 'flex-cards', 'flex-dashboard', 'todo-list', 'counter', 'accordion', 'tabs'];
6
6
 
7
7
  /**
8
8
  * Extracts indentation from a line
@@ -0,0 +1,67 @@
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}} - Accordion Component</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ </head>
9
+ <body>
10
+ <div class="container">
11
+ <div class="accordion-wrapper">
12
+ <h1>Frequently Asked Questions</h1>
13
+
14
+ <div class="accordion">
15
+ <div class="accordion-item">
16
+ <button class="accordion-header">
17
+ <span>What is this accordion component?</span>
18
+ <span class="icon">+</span>
19
+ </button>
20
+ <div class="accordion-content">
21
+ <div class="accordion-body">
22
+ This is a fully functional accordion component that uses DOM manipulation to toggle content visibility. Click on any header to expand or collapse the content.
23
+ </div>
24
+ </div>
25
+ </div>
26
+
27
+ <div class="accordion-item">
28
+ <button class="accordion-header">
29
+ <span>How does it work?</span>
30
+ <span class="icon">+</span>
31
+ </button>
32
+ <div class="accordion-content">
33
+ <div class="accordion-body">
34
+ The accordion uses JavaScript to toggle classes on DOM elements. When you click a header, it adds or removes the 'active' class to expand or collapse the content section.
35
+ </div>
36
+ </div>
37
+ </div>
38
+
39
+ <div class="accordion-item">
40
+ <button class="accordion-header">
41
+ <span>Can I customize the content?</span>
42
+ <span class="icon">+</span>
43
+ </button>
44
+ <div class="accordion-content">
45
+ <div class="accordion-body">
46
+ Absolutely! You can easily modify the HTML to add your own questions and answers. The styling and functionality will work with any content you add.
47
+ </div>
48
+ </div>
49
+ </div>
50
+
51
+ <div class="accordion-item">
52
+ <button class="accordion-header">
53
+ <span>Is it mobile responsive?</span>
54
+ <span class="icon">+</span>
55
+ </button>
56
+ <div class="accordion-content">
57
+ <div class="accordion-body">
58
+ Yes! This accordion is fully responsive and works great on all screen sizes - desktop, tablet, and mobile devices.
59
+ </div>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ <script src="script.js"></script>
66
+ </body>
67
+ </html>
@@ -0,0 +1,29 @@
1
+ // Accordion Component
2
+
3
+ const accordionHeaders = document.querySelectorAll('.accordion-header');
4
+
5
+ // Toggle accordion
6
+ function toggleAccordion(e) {
7
+ const header = e.currentTarget;
8
+ const item = header.parentElement;
9
+
10
+ // Close all other items
11
+ document.querySelectorAll('.accordion-item').forEach(accordionItem => {
12
+ if (accordionItem !== item) {
13
+ accordionItem.classList.remove('active');
14
+ }
15
+ });
16
+
17
+ // Toggle current item
18
+ item.classList.toggle('active');
19
+ }
20
+
21
+ // Add event listeners
22
+ accordionHeaders.forEach(header => {
23
+ header.addEventListener('click', toggleAccordion);
24
+ });
25
+
26
+ // Optional: Open first item by default
27
+ if (accordionHeaders.length > 0) {
28
+ accordionHeaders[0].parentElement.classList.add('active');
29
+ }
@@ -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
+ });
@@ -0,0 +1,173 @@
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: 700px;
20
+ }
21
+
22
+ .tabs-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
+ .tabs-wrapper h1 {
30
+ color: #333;
31
+ margin-bottom: 30px;
32
+ text-align: center;
33
+ font-size: 28px;
34
+ }
35
+
36
+ .tab-buttons {
37
+ display: flex;
38
+ gap: 8px;
39
+ border-bottom: 2px solid #e0e0e0;
40
+ margin-bottom: 30px;
41
+ flex-wrap: wrap;
42
+ }
43
+
44
+ .tab-button {
45
+ padding: 15px 20px;
46
+ background: none;
47
+ border: none;
48
+ cursor: pointer;
49
+ color: #666;
50
+ font-size: 14px;
51
+ font-weight: 600;
52
+ white-space: nowrap;
53
+ position: relative;
54
+ transition: all 0.3s;
55
+ display: flex;
56
+ align-items: center;
57
+ gap: 8px;
58
+ }
59
+
60
+ .tab-button:hover {
61
+ color: #333;
62
+ }
63
+
64
+ .tab-button.active {
65
+ color: #667eea;
66
+ }
67
+
68
+ .tab-button.active::after {
69
+ content: '';
70
+ position: absolute;
71
+ bottom: -2px;
72
+ left: 0;
73
+ right: 0;
74
+ height: 2px;
75
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
76
+ }
77
+
78
+ .tab-button .icon {
79
+ font-size: 18px;
80
+ }
81
+
82
+ .tab-contents {
83
+ position: relative;
84
+ }
85
+
86
+ .tab-content {
87
+ display: none;
88
+ animation: fadeIn 0.3s ease-in;
89
+ }
90
+
91
+ .tab-content.active {
92
+ display: block;
93
+ }
94
+
95
+ @keyframes fadeIn {
96
+ from {
97
+ opacity: 0;
98
+ transform: translateY(10px);
99
+ }
100
+ to {
101
+ opacity: 1;
102
+ transform: translateY(0);
103
+ }
104
+ }
105
+
106
+ .tab-content h2 {
107
+ color: #333;
108
+ margin-bottom: 15px;
109
+ font-size: 24px;
110
+ }
111
+
112
+ .tab-content p {
113
+ color: #666;
114
+ line-height: 1.6;
115
+ margin-bottom: 15px;
116
+ }
117
+
118
+ .tab-content ul {
119
+ list-style-position: inside;
120
+ color: #666;
121
+ line-height: 1.8;
122
+ margin-bottom: 15px;
123
+ }
124
+
125
+ .tab-content ul li {
126
+ margin-bottom: 8px;
127
+ }
128
+
129
+ .review {
130
+ background: #f8f9fa;
131
+ padding: 15px;
132
+ border-radius: 8px;
133
+ margin-bottom: 15px;
134
+ border-left: 4px solid #667eea;
135
+ }
136
+
137
+ .review p {
138
+ margin-bottom: 8px;
139
+ }
140
+
141
+ .review p:first-child {
142
+ font-weight: 600;
143
+ color: #333;
144
+ }
145
+
146
+ /* Responsive */
147
+ @media (max-width: 600px) {
148
+ .tabs-wrapper {
149
+ padding: 20px;
150
+ }
151
+
152
+ .tab-buttons {
153
+ gap: 4px;
154
+ }
155
+
156
+ .tab-button {
157
+ padding: 12px 14px;
158
+ font-size: 12px;
159
+ }
160
+
161
+ .tab-button .icon {
162
+ font-size: 16px;
163
+ }
164
+
165
+ .tabs-wrapper h1 {
166
+ font-size: 22px;
167
+ margin-bottom: 20px;
168
+ }
169
+
170
+ .tab-content h2 {
171
+ font-size: 18px;
172
+ }
173
+ }
@@ -0,0 +1,45 @@
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}} - Todo List</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ </head>
9
+ <body>
10
+ <div class="container">
11
+ <div class="todo-app">
12
+ <h1>My Tasks</h1>
13
+
14
+ <div class="input-container">
15
+ <input
16
+ type="text"
17
+ id="todoInput"
18
+ class="todo-input"
19
+ placeholder="Add a new task..."
20
+ >
21
+ <button id="addBtn" class="add-btn">Add Task</button>
22
+ </div>
23
+
24
+ <ul id="todoList" class="todo-list">
25
+ <li class="todo-item">
26
+ <input type="checkbox" class="todo-checkbox">
27
+ <span class="todo-text">Sample task 1</span>
28
+ <button class="delete-btn">✕</button>
29
+ </li>
30
+ <li class="todo-item">
31
+ <input type="checkbox" class="todo-checkbox">
32
+ <span class="todo-text">Sample task 2</span>
33
+ <button class="delete-btn">✕</button>
34
+ </li>
35
+ </ul>
36
+
37
+ <div class="stats">
38
+ <span>Total: <strong id="totalCount">2</strong></span>
39
+ <span>Completed: <strong id="completedCount">0</strong></span>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ <script src="script.js"></script>
44
+ </body>
45
+ </html>
@@ -0,0 +1,69 @@
1
+ // Todo List Application
2
+
3
+ const todoInput = document.getElementById('todoInput');
4
+ const addBtn = document.getElementById('addBtn');
5
+ const todoList = document.getElementById('todoList');
6
+ const totalCount = document.getElementById('totalCount');
7
+ const completedCount = document.getElementById('completedCount');
8
+
9
+ // Add new task
10
+ function addTodo() {
11
+ const text = todoInput.value.trim();
12
+
13
+ if (text === '') {
14
+ alert('Please enter a task!');
15
+ return;
16
+ }
17
+
18
+ // Create new todo item
19
+ const li = document.createElement('li');
20
+ li.className = 'todo-item';
21
+ li.innerHTML = `
22
+ <input type="checkbox" class="todo-checkbox">
23
+ <span class="todo-text">${text}</span>
24
+ <button class="delete-btn">✕</button>
25
+ `;
26
+
27
+ todoList.appendChild(li);
28
+ todoInput.value = '';
29
+ todoInput.focus();
30
+
31
+ updateStats();
32
+ attachEventListeners();
33
+ }
34
+
35
+ // Update statistics
36
+ function updateStats() {
37
+ const items = document.querySelectorAll('.todo-item');
38
+ const completed = document.querySelectorAll('.todo-item.completed');
39
+
40
+ totalCount.textContent = items.length;
41
+ completedCount.textContent = completed.length;
42
+ }
43
+
44
+ // Attach event listeners to new items
45
+ function attachEventListeners() {
46
+ document.querySelectorAll('.todo-checkbox').forEach(checkbox => {
47
+ checkbox.onclick = (e) => {
48
+ e.target.closest('.todo-item').classList.toggle('completed');
49
+ updateStats();
50
+ };
51
+ });
52
+
53
+ document.querySelectorAll('.delete-btn').forEach(btn => {
54
+ btn.onclick = (e) => {
55
+ e.target.closest('.todo-item').remove();
56
+ updateStats();
57
+ };
58
+ });
59
+ }
60
+
61
+ // Event listeners
62
+ addBtn.addEventListener('click', addTodo);
63
+ todoInput.addEventListener('keypress', (e) => {
64
+ if (e.key === 'Enter') addTodo();
65
+ });
66
+
67
+ // Initialize
68
+ attachEventListeners();
69
+ updateStats();
@@ -0,0 +1,138 @@
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: 500px;
20
+ }
21
+
22
+ .todo-app {
23
+ background: white;
24
+ border-radius: 12px;
25
+ padding: 30px;
26
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
27
+ }
28
+
29
+ .todo-app h1 {
30
+ color: #333;
31
+ margin-bottom: 25px;
32
+ text-align: center;
33
+ }
34
+
35
+ .input-container {
36
+ display: flex;
37
+ gap: 10px;
38
+ margin-bottom: 25px;
39
+ }
40
+
41
+ .todo-input {
42
+ flex: 1;
43
+ padding: 12px;
44
+ border: 2px solid #e0e0e0;
45
+ border-radius: 8px;
46
+ font-size: 16px;
47
+ transition: border-color 0.3s;
48
+ }
49
+
50
+ .todo-input:focus {
51
+ outline: none;
52
+ border-color: #667eea;
53
+ }
54
+
55
+ .add-btn {
56
+ padding: 12px 25px;
57
+ background: #667eea;
58
+ color: white;
59
+ border: none;
60
+ border-radius: 8px;
61
+ cursor: pointer;
62
+ font-weight: 600;
63
+ transition: background 0.3s;
64
+ }
65
+
66
+ .add-btn:hover {
67
+ background: #5568d3;
68
+ }
69
+
70
+ .todo-list {
71
+ list-style: none;
72
+ margin-bottom: 20px;
73
+ }
74
+
75
+ .todo-item {
76
+ display: flex;
77
+ align-items: center;
78
+ padding: 15px;
79
+ background: #f8f9fa;
80
+ border-radius: 8px;
81
+ margin-bottom: 10px;
82
+ transition: all 0.3s;
83
+ }
84
+
85
+ .todo-item:hover {
86
+ background: #e9ecef;
87
+ }
88
+
89
+ .todo-item.completed .todo-text {
90
+ text-decoration: line-through;
91
+ color: #999;
92
+ }
93
+
94
+ .todo-checkbox {
95
+ width: 20px;
96
+ height: 20px;
97
+ cursor: pointer;
98
+ margin-right: 15px;
99
+ }
100
+
101
+ .todo-text {
102
+ flex: 1;
103
+ color: #333;
104
+ font-size: 16px;
105
+ word-break: break-word;
106
+ }
107
+
108
+ .delete-btn {
109
+ background: #ff6b6b;
110
+ color: white;
111
+ border: none;
112
+ padding: 8px 12px;
113
+ border-radius: 6px;
114
+ cursor: pointer;
115
+ font-size: 16px;
116
+ transition: background 0.3s;
117
+ }
118
+
119
+ .delete-btn:hover {
120
+ background: #ff5252;
121
+ }
122
+
123
+ .stats {
124
+ display: flex;
125
+ justify-content: space-around;
126
+ padding-top: 20px;
127
+ border-top: 2px solid #e0e0e0;
128
+ color: #666;
129
+ }
130
+
131
+ .stats span {
132
+ font-size: 14px;
133
+ }
134
+
135
+ .stats strong {
136
+ color: #667eea;
137
+ font-size: 18px;
138
+ }