create-template-html-css 1.3.0 → 1.4.1
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 +48 -0
- package/INSERT-DEMO.md +31 -2
- package/README.md +55 -1
- package/bin/cli.js +119 -53
- package/package.json +5 -2
- package/src/generator.js +1 -1
- package/src/inserter.js +70 -23
- package/templates/flex-cards/index.html +276 -0
- package/templates/flex-cards/script.js +122 -0
- package/templates/flex-cards/style.css +556 -0
- package/templates/flex-dashboard/index.html +282 -0
- package/templates/flex-dashboard/script.js +149 -0
- package/templates/flex-dashboard/style.css +659 -0
- package/templates/flex-layout/index.html +185 -0
- package/templates/flex-layout/script.js +79 -0
- package/templates/flex-layout/style.css +336 -0
- package/test-insert.html +54 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,54 @@ 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.4.1] - 2025-01-29
|
|
9
|
+
|
|
10
|
+
### Improved
|
|
11
|
+
- **Enhanced Insert Feature**:
|
|
12
|
+
- Better indentation handling - respects existing HTML file formatting
|
|
13
|
+
- Improved duplicate detection - prevents inserting same component twice
|
|
14
|
+
- Unique component IDs - all styles/scripts get unique identifiers
|
|
15
|
+
- File validation - checks if HTML file exists before insertion
|
|
16
|
+
- All 19 components now available in insert command (was only 9 basic ones)
|
|
17
|
+
|
|
18
|
+
- **Improved CLI**:
|
|
19
|
+
- Better visual design with emojis and separators
|
|
20
|
+
- Organized component lists with categories
|
|
21
|
+
- File existence validation before insertion
|
|
22
|
+
- Enhanced help text and examples
|
|
23
|
+
- Better status messages with clear summaries
|
|
24
|
+
- Separated files as default for CSS insertion
|
|
25
|
+
|
|
26
|
+
### Technical Details
|
|
27
|
+
- Simplified indentation detection using HTML file's existing format
|
|
28
|
+
- Added `path` and `fs` imports for better file handling
|
|
29
|
+
- Improved error messages for better debugging
|
|
30
|
+
- Extended insert command with all template categories
|
|
31
|
+
|
|
32
|
+
## [1.4.0] - 2025-01-18
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- **Flexbox Layout Templates**:
|
|
36
|
+
- `flex-layout` - Comprehensive Flexbox patterns and examples (row, column, space-between, space-around, space-evenly, center, wrap, flex-grow, alignment variations, Holy Grail layout)
|
|
37
|
+
- `flex-cards` - Equal-height card layouts with Flexbox (pricing cards, product cards, team cards, testimonial cards with automatic equal heights and gradient backgrounds)
|
|
38
|
+
- `flex-dashboard` - Complete admin dashboard using Flexbox (collapsible sidebar, top bar with search, stats cards, bar chart, activity feed, top products, quick actions)
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
- Updated template count from 16 to 19 templates
|
|
42
|
+
- Enhanced `generator.js` and `inserter.js` with 3 new Flexbox components
|
|
43
|
+
- Updated CLI choices in `bin/cli.js` with Flexbox templates
|
|
44
|
+
- Enhanced `list` command to show new Flexbox category
|
|
45
|
+
- Updated README.md with detailed Flexbox template documentation
|
|
46
|
+
- Added `flexbox`, `flex-layout`, and `flex-dashboard` keywords to package.json
|
|
47
|
+
|
|
48
|
+
### Technical Details
|
|
49
|
+
- All Flexbox templates include full HTML, CSS, and JavaScript implementations
|
|
50
|
+
- Interactive sidebar collapse functionality
|
|
51
|
+
- Responsive design using pure Flexbox (no CSS Grid)
|
|
52
|
+
- Modern animations and hover effects
|
|
53
|
+
- Equal-height card systems without hacks
|
|
54
|
+
- Professional dashboard layouts with Flexbox
|
|
55
|
+
|
|
8
56
|
## [1.3.0] - 2025-01-18
|
|
9
57
|
|
|
10
58
|
### Added
|
package/INSERT-DEMO.md
CHANGED
|
@@ -2,7 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## How to Use the Insert Command
|
|
4
4
|
|
|
5
|
-
The `insert` command allows you to add pre-styled components to your existing HTML pages without creating new projects.
|
|
5
|
+
The `insert` command allows you to add pre-styled components to your existing HTML pages without creating new projects. Components are smartly integrated with proper indentation and ID attributes for easy customization.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
When inserting a component:
|
|
10
|
+
1. ✅ Detects existing indentation in your HTML file
|
|
11
|
+
2. ✅ Respects your code formatting style
|
|
12
|
+
3. ✅ Adds unique IDs to styles and scripts (e.g., `button-styles`, `button-script`)
|
|
13
|
+
4. ✅ Prevents duplicate insertions (warns if component already exists)
|
|
14
|
+
5. ✅ Validates HTML structure (checks for `<head>` and `<body>` tags)
|
|
6
15
|
|
|
7
16
|
## Example Usage
|
|
8
17
|
|
|
@@ -132,7 +141,9 @@ npm run insert
|
|
|
132
141
|
|
|
133
142
|
## Available Components
|
|
134
143
|
|
|
135
|
-
All
|
|
144
|
+
All 19 templates are available for insertion:
|
|
145
|
+
|
|
146
|
+
### Basic Components
|
|
136
147
|
- Button - Styled button variations
|
|
137
148
|
- Card - Product/content cards
|
|
138
149
|
- Form - Contact/input forms
|
|
@@ -140,3 +151,21 @@ All 7 templates are available for insertion:
|
|
|
140
151
|
- Modal - Dialog popups
|
|
141
152
|
- Footer - Page footer
|
|
142
153
|
- Hero - Hero sections with CTA
|
|
154
|
+
- Slider - Image carousel
|
|
155
|
+
- Table - Data tables with features
|
|
156
|
+
|
|
157
|
+
### Animation Templates
|
|
158
|
+
- Spinner - Loading animations
|
|
159
|
+
- Animated Card - Interactive card effects
|
|
160
|
+
- Typing Effect - Text animations
|
|
161
|
+
- Fade Gallery - Image gallery with effects
|
|
162
|
+
|
|
163
|
+
### Grid Layouts (CSS Grid)
|
|
164
|
+
- Grid Layout - CSS Grid examples
|
|
165
|
+
- Masonry Grid - Pinterest-style layout
|
|
166
|
+
- Dashboard Grid - Admin dashboard
|
|
167
|
+
|
|
168
|
+
### Flexbox Layouts
|
|
169
|
+
- Flex Layout - Flexbox patterns
|
|
170
|
+
- Flex Cards - Equal-height cards
|
|
171
|
+
- Flex Dashboard - Admin dashboard with Flexbox
|
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ 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
|
-
- 📦 **
|
|
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
|
|
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
|
|
@@ -407,6 +407,60 @@ Complete admin dashboard template:
|
|
|
407
407
|
- Mobile responsive
|
|
408
408
|
- Professional design
|
|
409
409
|
|
|
410
|
+
### 17. Flex Layout 📏
|
|
411
|
+
|
|
412
|
+
Comprehensive Flexbox patterns and examples:
|
|
413
|
+
|
|
414
|
+
**Includes:**
|
|
415
|
+
- Row and column layouts
|
|
416
|
+
- Space distribution patterns
|
|
417
|
+
- Alignment variations
|
|
418
|
+
- Flex-grow examples
|
|
419
|
+
- Nested flex containers
|
|
420
|
+
- Holy Grail layout
|
|
421
|
+
|
|
422
|
+
**Features:**
|
|
423
|
+
- Interactive examples
|
|
424
|
+
- Visual demonstrations
|
|
425
|
+
- Responsive design
|
|
426
|
+
- Modern Flexbox techniques
|
|
427
|
+
|
|
428
|
+
### 18. Flex Cards 🃏
|
|
429
|
+
|
|
430
|
+
Equal-height card layouts with Flexbox:
|
|
431
|
+
|
|
432
|
+
**Variations:**
|
|
433
|
+
- Basic equal-height cards
|
|
434
|
+
- Pricing cards
|
|
435
|
+
- Product cards
|
|
436
|
+
- Team member cards
|
|
437
|
+
- Testimonial cards
|
|
438
|
+
|
|
439
|
+
**Features:**
|
|
440
|
+
- Automatic equal heights
|
|
441
|
+
- Hover animations
|
|
442
|
+
- Gradient backgrounds
|
|
443
|
+
- Fully responsive
|
|
444
|
+
|
|
445
|
+
### 19. Flex Dashboard 🎛️
|
|
446
|
+
|
|
447
|
+
Admin dashboard built entirely with Flexbox:
|
|
448
|
+
|
|
449
|
+
**Components:**
|
|
450
|
+
- Collapsible sidebar
|
|
451
|
+
- Top search bar
|
|
452
|
+
- Stats cards
|
|
453
|
+
- Bar chart visualization
|
|
454
|
+
- Activity feed
|
|
455
|
+
- Top products list
|
|
456
|
+
- Quick actions
|
|
457
|
+
|
|
458
|
+
**Features:**
|
|
459
|
+
- Pure Flexbox layout
|
|
460
|
+
- Mobile responsive
|
|
461
|
+
- Interactive animations
|
|
462
|
+
- Professional design
|
|
463
|
+
|
|
410
464
|
|
|
411
465
|
## 💡 Examples
|
|
412
466
|
|
package/bin/cli.js
CHANGED
|
@@ -2,26 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
const { program } = require('commander');
|
|
4
4
|
const inquirer = require('inquirer').default || require('inquirer');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs').promises;
|
|
5
7
|
const { generateTemplate } = require('../src/generator');
|
|
6
8
|
const { insertComponent } = require('../src/inserter');
|
|
7
9
|
const chalk = require('chalk');
|
|
8
10
|
|
|
9
11
|
program
|
|
10
12
|
.name('create-template')
|
|
11
|
-
.description('
|
|
12
|
-
.version('1.
|
|
13
|
+
.description(chalk.cyan('🎨 Create HTML/CSS UI component templates in seconds'))
|
|
14
|
+
.version('1.4.0');
|
|
15
|
+
|
|
16
|
+
// Add intro message
|
|
17
|
+
program.on('--help', () => {
|
|
18
|
+
console.log('\n' + chalk.cyan('Examples:'));
|
|
19
|
+
console.log(' $ create-template create # Create a new template');
|
|
20
|
+
console.log(' $ create-template insert # Insert into existing HTML');
|
|
21
|
+
console.log(' $ create-template list # List all templates');
|
|
22
|
+
console.log('');
|
|
23
|
+
});
|
|
13
24
|
|
|
14
25
|
program
|
|
15
26
|
.command('create')
|
|
16
|
-
.description('Create a new HTML/CSS template')
|
|
27
|
+
.description(chalk.green('Create a new HTML/CSS template component'))
|
|
17
28
|
.action(async () => {
|
|
18
29
|
try {
|
|
30
|
+
console.log(chalk.cyan('\n✨ Creating a new template component...\n'));
|
|
31
|
+
|
|
19
32
|
const answers = await inquirer.prompt([
|
|
20
33
|
{
|
|
21
34
|
type: 'list',
|
|
22
35
|
name: 'component',
|
|
23
36
|
message: 'What component would you like to create?',
|
|
24
37
|
choices: [
|
|
38
|
+
new inquirer.Separator(chalk.gray('─ Basic Components')),
|
|
25
39
|
{ name: 'Button', value: 'button' },
|
|
26
40
|
{ name: 'Card', value: 'card' },
|
|
27
41
|
{ name: 'Form', value: 'form' },
|
|
@@ -31,13 +45,19 @@ program
|
|
|
31
45
|
{ name: 'Hero Section', value: 'hero' },
|
|
32
46
|
{ name: 'Slider', value: 'slider' },
|
|
33
47
|
{ name: 'Table', value: 'table' },
|
|
48
|
+
new inquirer.Separator(chalk.gray('─ Animation Templates')),
|
|
34
49
|
{ name: 'Spinner (Loading Animations)', value: 'spinner' },
|
|
35
50
|
{ name: 'Animated Card (Interactive Cards)', value: 'animated-card' },
|
|
36
51
|
{ name: 'Typing Effect (Text Animations)', value: 'typing-effect' },
|
|
37
52
|
{ name: 'Fade Gallery (Image Gallery)', value: 'fade-gallery' },
|
|
38
|
-
|
|
53
|
+
new inquirer.Separator(chalk.gray('─ Grid Layouts (CSS Grid)')),
|
|
54
|
+
{ name: 'Grid Layout', value: 'grid-layout' },
|
|
39
55
|
{ name: 'Masonry Grid (Pinterest-style)', value: 'masonry-grid' },
|
|
40
|
-
{ name: 'Dashboard Grid (Admin Panel)', value: 'dashboard-grid' }
|
|
56
|
+
{ name: 'Dashboard Grid (Admin Panel)', value: 'dashboard-grid' },
|
|
57
|
+
new inquirer.Separator(chalk.gray('─ Flexbox Layouts')),
|
|
58
|
+
{ name: 'Flex Layout (Flexbox Patterns)', value: 'flex-layout' },
|
|
59
|
+
{ name: 'Flex Cards (Equal-height cards)', value: 'flex-cards' },
|
|
60
|
+
{ name: 'Flex Dashboard (Flexbox Admin)', value: 'flex-dashboard' }
|
|
41
61
|
]
|
|
42
62
|
},
|
|
43
63
|
{
|
|
@@ -62,37 +82,50 @@ program
|
|
|
62
82
|
type: 'confirm',
|
|
63
83
|
name: 'includeJs',
|
|
64
84
|
message: 'Include JavaScript file?',
|
|
65
|
-
default:
|
|
85
|
+
default: true
|
|
66
86
|
}
|
|
67
87
|
]);
|
|
68
88
|
|
|
69
89
|
await generateTemplate(answers);
|
|
70
|
-
|
|
90
|
+
|
|
91
|
+
console.log('\n' + chalk.green('✓ Template created successfully!'));
|
|
92
|
+
console.log(chalk.gray(` Location: ./${answers.name}/`));
|
|
93
|
+
console.log(chalk.gray(` Files: index.html, style.css${answers.includeJs ? ', script.js' : ''}`));
|
|
94
|
+
console.log('');
|
|
71
95
|
} catch (error) {
|
|
72
|
-
console.error(chalk.red('Error
|
|
96
|
+
console.error(chalk.red('✗ Error:'), error.message);
|
|
73
97
|
process.exit(1);
|
|
74
98
|
}
|
|
75
99
|
});
|
|
76
100
|
|
|
77
101
|
program
|
|
78
102
|
.command('insert')
|
|
79
|
-
.description('Insert a component into an existing HTML page')
|
|
103
|
+
.description(chalk.green('Insert a component into an existing HTML page'))
|
|
80
104
|
.action(async () => {
|
|
81
105
|
try {
|
|
106
|
+
console.log(chalk.cyan('\n🚀 Inserting component into HTML file...\n'));
|
|
107
|
+
|
|
82
108
|
const answers = await inquirer.prompt([
|
|
83
109
|
{
|
|
84
110
|
type: 'input',
|
|
85
111
|
name: 'targetFile',
|
|
86
112
|
message: 'Enter the path to your HTML file:',
|
|
87
113
|
default: 'index.html',
|
|
88
|
-
validate: (input) => {
|
|
114
|
+
validate: async (input) => {
|
|
89
115
|
if (!input || input.trim().length === 0) {
|
|
90
116
|
return 'Please enter a file path';
|
|
91
117
|
}
|
|
92
118
|
if (!input.toLowerCase().endsWith('.html')) {
|
|
93
119
|
return 'File must be an HTML file (.html)';
|
|
94
120
|
}
|
|
95
|
-
|
|
121
|
+
|
|
122
|
+
// Check if file exists
|
|
123
|
+
try {
|
|
124
|
+
await fs.access(path.resolve(process.cwd(), input));
|
|
125
|
+
return true;
|
|
126
|
+
} catch {
|
|
127
|
+
return `File not found: ${input}`;
|
|
128
|
+
}
|
|
96
129
|
}
|
|
97
130
|
},
|
|
98
131
|
{
|
|
@@ -100,6 +133,7 @@ program
|
|
|
100
133
|
name: 'component',
|
|
101
134
|
message: 'Which component would you like to insert?',
|
|
102
135
|
choices: [
|
|
136
|
+
new inquirer.Separator(chalk.gray('─ Basic Components')),
|
|
103
137
|
{ name: 'Button', value: 'button' },
|
|
104
138
|
{ name: 'Card', value: 'card' },
|
|
105
139
|
{ name: 'Form', value: 'form' },
|
|
@@ -108,74 +142,106 @@ program
|
|
|
108
142
|
{ name: 'Footer', value: 'footer' },
|
|
109
143
|
{ name: 'Hero Section', value: 'hero' },
|
|
110
144
|
{ name: 'Slider', value: 'slider' },
|
|
111
|
-
{ name: 'Table', value: 'table' }
|
|
145
|
+
{ name: 'Table', value: 'table' },
|
|
146
|
+
new inquirer.Separator(chalk.gray('─ Animation Templates')),
|
|
147
|
+
{ name: 'Spinner', value: 'spinner' },
|
|
148
|
+
{ name: 'Animated Card', value: 'animated-card' },
|
|
149
|
+
{ name: 'Typing Effect', value: 'typing-effect' },
|
|
150
|
+
{ name: 'Fade Gallery', value: 'fade-gallery' },
|
|
151
|
+
new inquirer.Separator(chalk.gray('─ Grid Layouts')),
|
|
152
|
+
{ name: 'Grid Layout', value: 'grid-layout' },
|
|
153
|
+
{ name: 'Masonry Grid', value: 'masonry-grid' },
|
|
154
|
+
{ name: 'Dashboard Grid', value: 'dashboard-grid' },
|
|
155
|
+
new inquirer.Separator(chalk.gray('─ Flexbox Layouts')),
|
|
156
|
+
{ name: 'Flex Layout', value: 'flex-layout' },
|
|
157
|
+
{ name: 'Flex Cards', value: 'flex-cards' },
|
|
158
|
+
{ name: 'Flex Dashboard', value: 'flex-dashboard' }
|
|
112
159
|
]
|
|
113
160
|
},
|
|
114
|
-
{
|
|
115
|
-
type: 'list',
|
|
116
|
-
name: 'styleMode',
|
|
117
|
-
message: 'How should the CSS be added?',
|
|
118
|
-
choices: [
|
|
119
|
-
{ name: 'Inline (inside <style> tag)', value: 'inline' },
|
|
120
|
-
{ name: 'Separate file', value: 'separate' },
|
|
121
|
-
{ name: 'Skip (I\'ll add it manually)', value: 'skip' }
|
|
122
|
-
],
|
|
123
|
-
default: 'inline'
|
|
124
|
-
},
|
|
125
161
|
{
|
|
126
162
|
type: 'list',
|
|
127
163
|
name: 'scriptMode',
|
|
128
164
|
message: 'How should the JavaScript be added?',
|
|
129
165
|
choices: [
|
|
166
|
+
{ name: 'Separate file (recommended)', value: 'separate' },
|
|
130
167
|
{ name: 'Inline (inside <script> tag)', value: 'inline' },
|
|
131
|
-
{ name: 'Separate file', value: 'separate' },
|
|
132
168
|
{ name: 'Skip (I\'ll add it manually)', value: 'skip' }
|
|
133
169
|
],
|
|
134
|
-
default: '
|
|
170
|
+
default: 'separate'
|
|
135
171
|
}
|
|
136
172
|
]);
|
|
137
173
|
|
|
174
|
+
// CSS is always separate (external)
|
|
175
|
+
answers.styleMode = 'separate';
|
|
176
|
+
|
|
138
177
|
const result = await insertComponent(answers);
|
|
139
|
-
|
|
140
|
-
console.log(chalk.
|
|
141
|
-
console.log(chalk.cyan(
|
|
142
|
-
console.log(chalk.
|
|
143
|
-
console.log(chalk.
|
|
178
|
+
|
|
179
|
+
console.log('\n' + chalk.green('✓ Component inserted successfully!'));
|
|
180
|
+
console.log(chalk.cyan(' Summary:'));
|
|
181
|
+
console.log(chalk.gray(` File: ${path.relative(process.cwd(), result.targetFile)}`));
|
|
182
|
+
console.log(chalk.gray(` Component: ${chalk.bold(result.component)}`));
|
|
183
|
+
console.log(chalk.gray(` CSS: ${chalk.yellow('external file')}`));
|
|
184
|
+
console.log(chalk.gray(` JS: ${chalk.yellow(result.scriptMode)}`));
|
|
185
|
+
console.log(chalk.gray(`\n Component IDs: ${result.component}-styles, ${result.component}-script`));
|
|
186
|
+
console.log('');
|
|
144
187
|
} catch (error) {
|
|
145
|
-
console.error(chalk.red('Error
|
|
188
|
+
console.error('\n' + chalk.red('✗ Error:'), error.message);
|
|
146
189
|
process.exit(1);
|
|
147
190
|
}
|
|
148
191
|
});
|
|
149
192
|
|
|
150
193
|
program
|
|
151
194
|
.command('list')
|
|
152
|
-
.description('List all available templates')
|
|
195
|
+
.description(chalk.green('List all available templates'))
|
|
153
196
|
.action(() => {
|
|
154
|
-
console.log(chalk.blue('
|
|
155
|
-
|
|
156
|
-
console.log('
|
|
157
|
-
console.log('
|
|
158
|
-
console.log('
|
|
159
|
-
console.log('
|
|
160
|
-
console.log('
|
|
161
|
-
console.log('
|
|
162
|
-
console.log('
|
|
163
|
-
console.log('
|
|
164
|
-
console.log('
|
|
165
|
-
console.log(
|
|
166
|
-
|
|
167
|
-
console.log('
|
|
168
|
-
console.log('
|
|
169
|
-
console.log('
|
|
170
|
-
console.log(
|
|
171
|
-
console.log('
|
|
172
|
-
|
|
173
|
-
console.log('
|
|
197
|
+
console.log('\n' + chalk.blue('📦 Available Components (19 total)\n'));
|
|
198
|
+
|
|
199
|
+
console.log(chalk.yellow('━ Basic Components (9)'));
|
|
200
|
+
console.log(' button Styled button component');
|
|
201
|
+
console.log(' card Card component with image and content');
|
|
202
|
+
console.log(' form Form with input fields and validation');
|
|
203
|
+
console.log(' navigation Responsive navigation bar');
|
|
204
|
+
console.log(' modal Modal dialog component');
|
|
205
|
+
console.log(' footer Footer section');
|
|
206
|
+
console.log(' hero Hero section with CTA button');
|
|
207
|
+
console.log(' slider Image carousel with navigation');
|
|
208
|
+
console.log(' table Data table with search and filtering');
|
|
209
|
+
|
|
210
|
+
console.log('\n' + chalk.magenta('━ Animation Templates (4)'));
|
|
211
|
+
console.log(' spinner 5 loading spinner variations');
|
|
212
|
+
console.log(' animated-card 6 interactive card animations');
|
|
213
|
+
console.log(' typing-effect Text typing animations');
|
|
214
|
+
console.log(' fade-gallery Image gallery with fade effects');
|
|
215
|
+
|
|
216
|
+
console.log('\n' + chalk.cyan('━ Grid Layouts (3)'));
|
|
217
|
+
console.log(' grid-layout CSS Grid patterns and examples');
|
|
218
|
+
console.log(' masonry-grid Pinterest-style masonry layout');
|
|
219
|
+
console.log(' dashboard-grid Complete admin dashboard (Grid)');
|
|
220
|
+
|
|
221
|
+
console.log('\n' + chalk.green('━ Flexbox Layouts (3)'));
|
|
222
|
+
console.log(' flex-layout Flexbox patterns and examples');
|
|
223
|
+
console.log(' flex-cards Equal-height card layouts');
|
|
224
|
+
console.log(' flex-dashboard Complete admin dashboard (Flexbox)');
|
|
225
|
+
|
|
226
|
+
console.log('\n' + chalk.gray('Usage:'));
|
|
227
|
+
console.log(' create-template create Create a new component');
|
|
228
|
+
console.log(' create-template insert Insert into HTML file');
|
|
174
229
|
console.log('');
|
|
175
230
|
});
|
|
176
231
|
|
|
177
232
|
program.parse(process.argv);
|
|
178
233
|
|
|
179
234
|
if (!process.argv.slice(2).length) {
|
|
180
|
-
|
|
235
|
+
console.log('\n' + chalk.cyan('🎨 Create HTML/CSS UI Templates\n'));
|
|
236
|
+
console.log(chalk.white('Usage: create-template [command]') + '\n');
|
|
237
|
+
console.log(chalk.yellow('Commands:'));
|
|
238
|
+
console.log(' create Create a new template component');
|
|
239
|
+
console.log(' insert Insert component into existing HTML file');
|
|
240
|
+
console.log(' list Show all available templates');
|
|
241
|
+
console.log(' help Display help information\n');
|
|
242
|
+
console.log(chalk.gray('Examples:'));
|
|
243
|
+
console.log(' $ create-template create # Interactive template creation');
|
|
244
|
+
console.log(' $ create-template insert # Interactive component insertion');
|
|
245
|
+
console.log(' $ create-template list # View all 19 templates');
|
|
246
|
+
console.log(' $ create-template --help # Show full help\n');
|
|
181
247
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-template-html-css",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "CLI tool to generate HTML and CSS templates for common UI elements",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -35,7 +35,10 @@
|
|
|
35
35
|
"typing-effect",
|
|
36
36
|
"gallery",
|
|
37
37
|
"responsive",
|
|
38
|
-
"modern-ui"
|
|
38
|
+
"modern-ui",
|
|
39
|
+
"flexbox",
|
|
40
|
+
"flex-layout",
|
|
41
|
+
"flex-dashboard"
|
|
39
42
|
],
|
|
40
43
|
"author": "Ben Shabbat <benshabbat@example.com> (https://github.com/benshabbat)",
|
|
41
44
|
"license": "MIT",
|
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'];
|
|
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'];
|
|
6
6
|
|
|
7
7
|
// Security: Sanitize filename to prevent path traversal
|
|
8
8
|
function sanitizeFilename(filename) {
|
package/src/inserter.js
CHANGED
|
@@ -2,7 +2,32 @@ 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'];
|
|
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'];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Extracts indentation from a line
|
|
9
|
+
*/
|
|
10
|
+
function getIndentation(line) {
|
|
11
|
+
const match = line.match(/^(\s*)/);
|
|
12
|
+
return match ? match[1] : '';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Checks if a component is already inserted in the HTML
|
|
17
|
+
*/
|
|
18
|
+
function isComponentAlreadyInserted(htmlContent, component) {
|
|
19
|
+
const commentPattern = new RegExp(`<!-- ${component.toUpperCase()} Component -->`, 'i');
|
|
20
|
+
return commentPattern.test(htmlContent);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Gets the indentation level used in an HTML file
|
|
25
|
+
*/
|
|
26
|
+
function getHtmlIndentation(htmlContent) {
|
|
27
|
+
// Look for any indented line to determine the standard indentation
|
|
28
|
+
const match = htmlContent.match(/\n(\s+)\S/);
|
|
29
|
+
return match ? match[1] : ' '; // default to 4 spaces
|
|
30
|
+
}
|
|
6
31
|
|
|
7
32
|
async function insertComponent(options) {
|
|
8
33
|
const { component, targetFile, styleMode, scriptMode } = options;
|
|
@@ -23,12 +48,26 @@ async function insertComponent(options) {
|
|
|
23
48
|
// Read target HTML file
|
|
24
49
|
let htmlContent = await fs.readFile(targetPath, 'utf-8');
|
|
25
50
|
|
|
51
|
+
// Check if component is already inserted
|
|
52
|
+
if (isComponentAlreadyInserted(htmlContent, component)) {
|
|
53
|
+
throw new Error(`Component "${component}" is already inserted in this file`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Validate HTML structure
|
|
57
|
+
if (!htmlContent.includes('</body>')) {
|
|
58
|
+
throw new Error('Target HTML file does not have a closing </body> tag');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!htmlContent.includes('</head>')) {
|
|
62
|
+
throw new Error('Target HTML file does not have a </head> tag');
|
|
63
|
+
}
|
|
64
|
+
|
|
26
65
|
// Get component templates
|
|
27
66
|
const templateDir = path.join(__dirname, '..', 'templates', component);
|
|
28
67
|
const componentHtml = await fs.readFile(path.join(templateDir, 'index.html'), 'utf-8');
|
|
29
68
|
const componentCss = await fs.readFile(path.join(templateDir, 'style.css'), 'utf-8');
|
|
30
69
|
|
|
31
|
-
// Extract component body content
|
|
70
|
+
// Extract component body content
|
|
32
71
|
const bodyMatch = componentHtml.match(/<body[^>]*>([\s\S]*)<\/body>/i);
|
|
33
72
|
if (!bodyMatch) {
|
|
34
73
|
throw new Error('Invalid component template structure');
|
|
@@ -36,31 +75,36 @@ async function insertComponent(options) {
|
|
|
36
75
|
|
|
37
76
|
let componentBody = bodyMatch[1].trim();
|
|
38
77
|
|
|
78
|
+
// Get indentation used in the HTML file
|
|
79
|
+
const baseIndent = getHtmlIndentation(htmlContent);
|
|
80
|
+
|
|
81
|
+
// Normalize component body indentation
|
|
82
|
+
const lines = componentBody.split('\n').map(line => {
|
|
83
|
+
if (line.trim() === '') return '';
|
|
84
|
+
return baseIndent + line.trim();
|
|
85
|
+
}).join('\n');
|
|
86
|
+
componentBody = lines;
|
|
87
|
+
|
|
39
88
|
// Insert component HTML before closing </body> tag
|
|
40
|
-
|
|
41
|
-
htmlContent = htmlContent.replace('</body>', `\n <!-- ${component.toUpperCase()} Component -->\n${componentBody}\n</body>`);
|
|
42
|
-
} else {
|
|
43
|
-
throw new Error('Target HTML file does not have a closing </body> tag');
|
|
44
|
-
}
|
|
89
|
+
htmlContent = htmlContent.replace('</body>', `${baseIndent}<!-- ${component.toUpperCase()} Component -->\n${componentBody}\n\n</body>`);
|
|
45
90
|
|
|
46
91
|
// Handle CSS
|
|
47
92
|
if (styleMode === 'inline') {
|
|
48
|
-
//
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
93
|
+
// Normalize CSS indentation
|
|
94
|
+
const normalizedCss = componentCss.split('\n').map(line => {
|
|
95
|
+
if (line.trim() === '') return '';
|
|
96
|
+
return baseIndent + ' ' + line.trim();
|
|
97
|
+
}).join('\n');
|
|
98
|
+
|
|
99
|
+
htmlContent = htmlContent.replace('</head>', `${baseIndent}<style id="${component}-styles">\n${baseIndent} /* ${component.toUpperCase()} Component Styles */\n${normalizedCss}\n${baseIndent}</style>\n</head>`);
|
|
53
100
|
} else if (styleMode === 'separate') {
|
|
54
101
|
// Create separate CSS file
|
|
55
102
|
const cssFileName = `${component}-component.css`;
|
|
56
103
|
const cssPath = path.join(path.dirname(targetPath), cssFileName);
|
|
57
|
-
await fs.writeFile(cssPath, `/* ${component.toUpperCase()} Component Styles */\n${componentCss}`);
|
|
104
|
+
await fs.writeFile(cssPath, `/* ${component.toUpperCase()} Component Styles */\n\n${componentCss}`);
|
|
58
105
|
|
|
59
106
|
// Add link to CSS file
|
|
60
|
-
|
|
61
|
-
if (htmlContent.includes('</head>')) {
|
|
62
|
-
htmlContent = htmlContent.replace('</head>', `${linkTag}\n</head>`);
|
|
63
|
-
}
|
|
107
|
+
htmlContent = htmlContent.replace('</head>', `${baseIndent}<link rel="stylesheet" href="${cssFileName}">\n</head>`);
|
|
64
108
|
}
|
|
65
109
|
|
|
66
110
|
// Handle JavaScript
|
|
@@ -68,18 +112,21 @@ async function insertComponent(options) {
|
|
|
68
112
|
const componentJs = await fs.readFile(path.join(templateDir, 'script.js'), 'utf-8');
|
|
69
113
|
|
|
70
114
|
if (scriptMode === 'inline') {
|
|
71
|
-
//
|
|
72
|
-
const
|
|
73
|
-
|
|
115
|
+
// Normalize JS indentation
|
|
116
|
+
const normalizedJs = componentJs.split('\n').map(line => {
|
|
117
|
+
if (line.trim() === '') return '';
|
|
118
|
+
return baseIndent + ' ' + line.trim();
|
|
119
|
+
}).join('\n');
|
|
120
|
+
|
|
121
|
+
htmlContent = htmlContent.replace('</body>', `${baseIndent}<script id="${component}-script">\n${baseIndent} // ${component.toUpperCase()} Component Script\n${normalizedJs}\n${baseIndent}</script>\n</body>`);
|
|
74
122
|
} else if (scriptMode === 'separate') {
|
|
75
123
|
// Create separate JS file
|
|
76
124
|
const jsFileName = `${component}-component.js`;
|
|
77
125
|
const jsPath = path.join(path.dirname(targetPath), jsFileName);
|
|
78
|
-
await fs.writeFile(jsPath, `// ${component.toUpperCase()} Component Script\n${componentJs}`);
|
|
126
|
+
await fs.writeFile(jsPath, `// ${component.toUpperCase()} Component Script\n\n${componentJs}`);
|
|
79
127
|
|
|
80
128
|
// Add script tag
|
|
81
|
-
|
|
82
|
-
htmlContent = htmlContent.replace('</body>', `${scriptTag}</body>`);
|
|
129
|
+
htmlContent = htmlContent.replace('</body>', `${baseIndent}<script src="${jsFileName}" id="${component}-script"></script>\n</body>`);
|
|
83
130
|
}
|
|
84
131
|
} catch (error) {
|
|
85
132
|
// No JavaScript file for this component, skip
|