create-template-html-css 1.0.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/CONTRIBUTING.md +62 -0
- package/INSERT-DEMO.md +142 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +195 -0
- package/README.md +0 -0
- package/SECURITY.md +95 -0
- package/SHOWCASE.html +342 -0
- package/bin/cli.js +158 -0
- package/package.json +50 -0
- package/src/generator.js +64 -0
- package/src/index.js +1 -0
- package/src/inserter.js +99 -0
- package/templates/button/index.html +32 -0
- package/templates/button/script.js +15 -0
- package/templates/button/style.css +108 -0
- package/templates/card/index.html +52 -0
- package/templates/card/script.js +9 -0
- package/templates/card/style.css +103 -0
- package/templates/footer/index.html +67 -0
- package/templates/footer/script.js +43 -0
- package/templates/footer/style.css +165 -0
- package/templates/form/index.html +54 -0
- package/templates/form/script.js +34 -0
- package/templates/form/style.css +137 -0
- package/templates/hero/index.html +73 -0
- package/templates/hero/script.js +80 -0
- package/templates/hero/style.css +272 -0
- package/templates/modal/index.html +63 -0
- package/templates/modal/script.js +69 -0
- package/templates/modal/style.css +223 -0
- package/templates/navigation/index.html +69 -0
- package/templates/navigation/script.js +61 -0
- package/templates/navigation/style.css +161 -0
package/SHOWCASE.html
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="he" dir="rtl">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Create Template HTML/CSS - Showcase</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
16
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
|
+
min-height: 100vh;
|
|
18
|
+
padding: 40px 20px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.container {
|
|
22
|
+
max-width: 1200px;
|
|
23
|
+
margin: 0 auto;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.header {
|
|
27
|
+
text-align: center;
|
|
28
|
+
color: white;
|
|
29
|
+
margin-bottom: 60px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.header h1 {
|
|
33
|
+
font-size: 3rem;
|
|
34
|
+
margin-bottom: 20px;
|
|
35
|
+
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.header p {
|
|
39
|
+
font-size: 1.3rem;
|
|
40
|
+
opacity: 0.9;
|
|
41
|
+
margin-bottom: 30px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.badge {
|
|
45
|
+
display: inline-block;
|
|
46
|
+
background: rgba(255, 255, 255, 0.2);
|
|
47
|
+
padding: 8px 20px;
|
|
48
|
+
border-radius: 50px;
|
|
49
|
+
backdrop-filter: blur(10px);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.templates-grid {
|
|
53
|
+
display: grid;
|
|
54
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
55
|
+
gap: 30px;
|
|
56
|
+
margin-bottom: 60px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.template-card {
|
|
60
|
+
background: white;
|
|
61
|
+
border-radius: 15px;
|
|
62
|
+
overflow: hidden;
|
|
63
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
|
64
|
+
transition: all 0.3s ease;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.template-card:hover {
|
|
68
|
+
transform: translateY(-10px);
|
|
69
|
+
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.card-header {
|
|
73
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
74
|
+
color: white;
|
|
75
|
+
padding: 25px;
|
|
76
|
+
text-align: center;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.card-icon {
|
|
80
|
+
font-size: 3rem;
|
|
81
|
+
margin-bottom: 10px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.card-title {
|
|
85
|
+
font-size: 1.8rem;
|
|
86
|
+
margin: 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.card-body {
|
|
90
|
+
padding: 25px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.card-description {
|
|
94
|
+
color: #666;
|
|
95
|
+
line-height: 1.6;
|
|
96
|
+
margin-bottom: 20px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.features {
|
|
100
|
+
list-style: none;
|
|
101
|
+
margin-bottom: 20px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.features li {
|
|
105
|
+
color: #555;
|
|
106
|
+
padding: 8px 0;
|
|
107
|
+
border-bottom: 1px solid #eee;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.features li:last-child {
|
|
111
|
+
border-bottom: none;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.features li::before {
|
|
115
|
+
content: '✓';
|
|
116
|
+
color: #28a745;
|
|
117
|
+
font-weight: bold;
|
|
118
|
+
margin-left: 10px;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.installation {
|
|
122
|
+
background: white;
|
|
123
|
+
border-radius: 15px;
|
|
124
|
+
padding: 40px;
|
|
125
|
+
margin-bottom: 40px;
|
|
126
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.installation h2 {
|
|
130
|
+
color: #333;
|
|
131
|
+
margin-bottom: 20px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.code-block {
|
|
135
|
+
background: #2d3748;
|
|
136
|
+
color: #63b3ed;
|
|
137
|
+
padding: 20px;
|
|
138
|
+
border-radius: 10px;
|
|
139
|
+
font-family: 'Courier New', monospace;
|
|
140
|
+
overflow-x: auto;
|
|
141
|
+
margin: 15px 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.footer-section {
|
|
145
|
+
text-align: center;
|
|
146
|
+
color: white;
|
|
147
|
+
padding: 40px 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.footer-section a {
|
|
151
|
+
color: white;
|
|
152
|
+
text-decoration: none;
|
|
153
|
+
margin: 0 15px;
|
|
154
|
+
opacity: 0.8;
|
|
155
|
+
transition: opacity 0.3s ease;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.footer-section a:hover {
|
|
159
|
+
opacity: 1;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@media (max-width: 768px) {
|
|
163
|
+
.header h1 {
|
|
164
|
+
font-size: 2rem;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.templates-grid {
|
|
168
|
+
grid-template-columns: 1fr;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
</style>
|
|
172
|
+
</head>
|
|
173
|
+
<body>
|
|
174
|
+
<div class="container">
|
|
175
|
+
<div class="header">
|
|
176
|
+
<div class="badge">🎨 Open Source</div>
|
|
177
|
+
<h1>Create Template HTML/CSS</h1>
|
|
178
|
+
<p>צור רכיבי UI מעוצבים תוך שניות עם CLI חזק</p>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<div class="installation">
|
|
182
|
+
<h2>🚀 התקנה והתחלה מהירה</h2>
|
|
183
|
+
<div class="code-block">
|
|
184
|
+
# Clone the repository<br>
|
|
185
|
+
git clone https://github.com/benshabbat/create-template-html-css.git<br>
|
|
186
|
+
cd create-template-html-css<br>
|
|
187
|
+
<br>
|
|
188
|
+
# Install dependencies<br>
|
|
189
|
+
npm install<br>
|
|
190
|
+
<br>
|
|
191
|
+
# Create a template<br>
|
|
192
|
+
npm run create
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<h2 style="color: white; text-align: center; margin-bottom: 40px; font-size: 2.5rem;">
|
|
197
|
+
7 טמפלייטים מעוצבים ומוכנים לשימוש
|
|
198
|
+
</h2>
|
|
199
|
+
|
|
200
|
+
<div class="templates-grid">
|
|
201
|
+
<div class="template-card">
|
|
202
|
+
<div class="card-header">
|
|
203
|
+
<div class="card-icon">🔘</div>
|
|
204
|
+
<h3 class="card-title">Button</h3>
|
|
205
|
+
</div>
|
|
206
|
+
<div class="card-body">
|
|
207
|
+
<p class="card-description">
|
|
208
|
+
כפתורים מעוצבים עם מגוון סגנונות ואפקטים
|
|
209
|
+
</p>
|
|
210
|
+
<ul class="features">
|
|
211
|
+
<li>6 סוגי כפתורים שונים</li>
|
|
212
|
+
<li>אפקטי Hover מתקדמים</li>
|
|
213
|
+
<li>גרדיאנטים צבעוניים</li>
|
|
214
|
+
<li>אנימציות חלקות</li>
|
|
215
|
+
</ul>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
<div class="template-card">
|
|
220
|
+
<div class="card-header">
|
|
221
|
+
<div class="card-icon">🃏</div>
|
|
222
|
+
<h3 class="card-title">Card</h3>
|
|
223
|
+
</div>
|
|
224
|
+
<div class="card-body">
|
|
225
|
+
<p class="card-description">
|
|
226
|
+
כרטיסים אלגנטיים עם תמונה, תוכן וכפתור פעולה
|
|
227
|
+
</p>
|
|
228
|
+
<ul class="features">
|
|
229
|
+
<li>Grid Responsive</li>
|
|
230
|
+
<li>אפקט הגדלת תמונה</li>
|
|
231
|
+
<li>צללים מתקדמים</li>
|
|
232
|
+
<li>עיצוב מודרני</li>
|
|
233
|
+
</ul>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
|
|
237
|
+
<div class="template-card">
|
|
238
|
+
<div class="card-header">
|
|
239
|
+
<div class="card-icon">📝</div>
|
|
240
|
+
<h3 class="card-title">Form</h3>
|
|
241
|
+
</div>
|
|
242
|
+
<div class="card-body">
|
|
243
|
+
<p class="card-description">
|
|
244
|
+
טופס יצירת קשר מלא עם ולידציה בזמן אמת
|
|
245
|
+
</p>
|
|
246
|
+
<ul class="features">
|
|
247
|
+
<li>מגוון שדות קלט</li>
|
|
248
|
+
<li>ולידציה אוטומטית</li>
|
|
249
|
+
<li>אפקטי Focus מתקדמים</li>
|
|
250
|
+
<li>עיצוב נקי ומודרני</li>
|
|
251
|
+
</ul>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
<div class="template-card">
|
|
256
|
+
<div class="card-header">
|
|
257
|
+
<div class="card-icon">🧭</div>
|
|
258
|
+
<h3 class="card-title">Navigation</h3>
|
|
259
|
+
</div>
|
|
260
|
+
<div class="card-body">
|
|
261
|
+
<p class="card-description">
|
|
262
|
+
תפריט ניווט responsive עם תמיכה מלאה במובייל
|
|
263
|
+
</p>
|
|
264
|
+
<ul class="features">
|
|
265
|
+
<li>Fixed למעלה</li>
|
|
266
|
+
<li>תפריט המבורגר</li>
|
|
267
|
+
<li>Smooth Scroll</li>
|
|
268
|
+
<li>הדגשת דף פעיל</li>
|
|
269
|
+
</ul>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
<div class="template-card">
|
|
274
|
+
<div class="card-header">
|
|
275
|
+
<div class="card-icon">💬</div>
|
|
276
|
+
<h3 class="card-title">Modal</h3>
|
|
277
|
+
</div>
|
|
278
|
+
<div class="card-body">
|
|
279
|
+
<p class="card-description">
|
|
280
|
+
חלונות מודליים מעוצבים לכל מטרה
|
|
281
|
+
</p>
|
|
282
|
+
<ul class="features">
|
|
283
|
+
<li>3 סוגי מודלים</li>
|
|
284
|
+
<li>Backdrop Blur</li>
|
|
285
|
+
<li>אנימציות פתיחה</li>
|
|
286
|
+
<li>סגירה ב-ESC</li>
|
|
287
|
+
</ul>
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
290
|
+
|
|
291
|
+
<div class="template-card">
|
|
292
|
+
<div class="card-header">
|
|
293
|
+
<div class="card-icon">📄</div>
|
|
294
|
+
<h3 class="card-title">Footer</h3>
|
|
295
|
+
</div>
|
|
296
|
+
<div class="card-body">
|
|
297
|
+
<p class="card-description">
|
|
298
|
+
Footer מקצועי עם עמודות ורשתות חברתיות
|
|
299
|
+
</p>
|
|
300
|
+
<ul class="features">
|
|
301
|
+
<li>Grid Responsive</li>
|
|
302
|
+
<li>קישורים מאורגנים</li>
|
|
303
|
+
<li>פרטי קשר</li>
|
|
304
|
+
<li>אנימציות Scroll</li>
|
|
305
|
+
</ul>
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
|
|
309
|
+
<div class="template-card">
|
|
310
|
+
<div class="card-header">
|
|
311
|
+
<div class="card-icon">🎯</div>
|
|
312
|
+
<h3 class="card-title">Hero</h3>
|
|
313
|
+
</div>
|
|
314
|
+
<div class="card-body">
|
|
315
|
+
<p class="card-description">
|
|
316
|
+
3 סוגי Hero sections מרשימים לדף הבית
|
|
317
|
+
</p>
|
|
318
|
+
<ul class="features">
|
|
319
|
+
<li>גרדיאנט/תמונה רקע</li>
|
|
320
|
+
<li>אנימציות טקסט</li>
|
|
321
|
+
<li>אפקט Parallax</li>
|
|
322
|
+
<li>CTA Buttons</li>
|
|
323
|
+
</ul>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
|
|
328
|
+
<div class="footer-section">
|
|
329
|
+
<h3 style="margin-bottom: 20px;">צור קשר ותרום</h3>
|
|
330
|
+
<div>
|
|
331
|
+
<a href="https://github.com/benshabbat/create-template-html-css">📦 GitHub</a>
|
|
332
|
+
<a href="https://github.com/benshabbat/create-template-html-css/issues">🐛 Issues</a>
|
|
333
|
+
<a href="CONTRIBUTING.md">🤝 Contributing</a>
|
|
334
|
+
<a href="LICENSE">📜 License</a>
|
|
335
|
+
</div>
|
|
336
|
+
<p style="margin-top: 30px; opacity: 0.8;">
|
|
337
|
+
Made with ❤️ by Ben Shabbat
|
|
338
|
+
</p>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
</body>
|
|
342
|
+
</html>
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const inquirer = require('inquirer').default || require('inquirer');
|
|
5
|
+
const { generateTemplate } = require('../src/generator');
|
|
6
|
+
const { insertComponent } = require('../src/inserter');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
|
|
9
|
+
program
|
|
10
|
+
.name('create-template')
|
|
11
|
+
.description('CLI tool to generate HTML and CSS templates')
|
|
12
|
+
.version('1.0.0');
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.command('create')
|
|
16
|
+
.description('Create a new HTML/CSS template')
|
|
17
|
+
.action(async () => {
|
|
18
|
+
try {
|
|
19
|
+
const answers = await inquirer.prompt([
|
|
20
|
+
{
|
|
21
|
+
type: 'list',
|
|
22
|
+
name: 'component',
|
|
23
|
+
message: 'What component would you like to create?',
|
|
24
|
+
choices: [
|
|
25
|
+
{ name: 'Button', value: 'button' },
|
|
26
|
+
{ name: 'Card', value: 'card' },
|
|
27
|
+
{ name: 'Form', value: 'form' },
|
|
28
|
+
{ name: 'Navigation', value: 'navigation' },
|
|
29
|
+
{ name: 'Modal', value: 'modal' },
|
|
30
|
+
{ name: 'Footer', value: 'footer' },
|
|
31
|
+
{ name: 'Hero Section', value: 'hero' }
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
type: 'input',
|
|
36
|
+
name: 'name',
|
|
37
|
+
message: 'Enter a name for your component:',
|
|
38
|
+
default: (answers) => answers.component,
|
|
39
|
+
validate: (input) => {
|
|
40
|
+
if (!input || input.trim().length === 0) {
|
|
41
|
+
return 'Please enter a valid name';
|
|
42
|
+
}
|
|
43
|
+
if (input.includes('..') || input.includes('/') || input.includes('\\')) {
|
|
44
|
+
return 'Name cannot contain path separators or parent directory references';
|
|
45
|
+
}
|
|
46
|
+
if (input.length > 100) {
|
|
47
|
+
return 'Name is too long (max 100 characters)';
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: 'confirm',
|
|
54
|
+
name: 'includeJs',
|
|
55
|
+
message: 'Include JavaScript file?',
|
|
56
|
+
default: false
|
|
57
|
+
}
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
await generateTemplate(answers);
|
|
61
|
+
console.log(chalk.green('✓ Template created successfully!'));
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(chalk.red('Error creating template:'), error.message);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
program
|
|
69
|
+
.command('insert')
|
|
70
|
+
.description('Insert a component into an existing HTML page')
|
|
71
|
+
.action(async () => {
|
|
72
|
+
try {
|
|
73
|
+
const answers = await inquirer.prompt([
|
|
74
|
+
{
|
|
75
|
+
type: 'input',
|
|
76
|
+
name: 'targetFile',
|
|
77
|
+
message: 'Enter the path to your HTML file:',
|
|
78
|
+
default: 'index.html',
|
|
79
|
+
validate: (input) => {
|
|
80
|
+
if (!input || input.trim().length === 0) {
|
|
81
|
+
return 'Please enter a file path';
|
|
82
|
+
}
|
|
83
|
+
if (!input.toLowerCase().endsWith('.html')) {
|
|
84
|
+
return 'File must be an HTML file (.html)';
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
type: 'list',
|
|
91
|
+
name: 'component',
|
|
92
|
+
message: 'Which component would you like to insert?',
|
|
93
|
+
choices: [
|
|
94
|
+
{ name: 'Button', value: 'button' },
|
|
95
|
+
{ name: 'Card', value: 'card' },
|
|
96
|
+
{ name: 'Form', value: 'form' },
|
|
97
|
+
{ name: 'Navigation', value: 'navigation' },
|
|
98
|
+
{ name: 'Modal', value: 'modal' },
|
|
99
|
+
{ name: 'Footer', value: 'footer' },
|
|
100
|
+
{ name: 'Hero Section', value: 'hero' }
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
type: 'list',
|
|
105
|
+
name: 'styleMode',
|
|
106
|
+
message: 'How should the CSS be added?',
|
|
107
|
+
choices: [
|
|
108
|
+
{ name: 'Inline (inside <style> tag)', value: 'inline' },
|
|
109
|
+
{ name: 'Separate file', value: 'separate' },
|
|
110
|
+
{ name: 'Skip (I\'ll add it manually)', value: 'skip' }
|
|
111
|
+
],
|
|
112
|
+
default: 'inline'
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
type: 'list',
|
|
116
|
+
name: 'scriptMode',
|
|
117
|
+
message: 'How should the JavaScript be added?',
|
|
118
|
+
choices: [
|
|
119
|
+
{ name: 'Inline (inside <script> 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
|
+
]);
|
|
126
|
+
|
|
127
|
+
const result = await insertComponent(answers);
|
|
128
|
+
console.log(chalk.green('\n✓ Component inserted successfully!'));
|
|
129
|
+
console.log(chalk.cyan(` File: ${result.targetFile}`));
|
|
130
|
+
console.log(chalk.cyan(` Component: ${result.component}`));
|
|
131
|
+
console.log(chalk.cyan(` CSS: ${result.styleMode}`));
|
|
132
|
+
console.log(chalk.cyan(` JS: ${result.scriptMode}`));
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error(chalk.red('Error inserting component:'), error.message);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
program
|
|
140
|
+
.command('list')
|
|
141
|
+
.description('List all available templates')
|
|
142
|
+
.action(() => {
|
|
143
|
+
console.log(chalk.blue('\nAvailable templates:\n'));
|
|
144
|
+
console.log(' • Button - Styled button component');
|
|
145
|
+
console.log(' • Card - Card component with image and content');
|
|
146
|
+
console.log(' • Form - Form with input fields');
|
|
147
|
+
console.log(' • Navigation - Navigation bar');
|
|
148
|
+
console.log(' • Modal - Modal dialog');
|
|
149
|
+
console.log(' • Footer - Footer section');
|
|
150
|
+
console.log(' • Hero - Hero section with CTA');
|
|
151
|
+
console.log('');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
program.parse(process.argv);
|
|
155
|
+
|
|
156
|
+
if (!process.argv.slice(2).length) {
|
|
157
|
+
program.outputHelp();
|
|
158
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-template-html-css",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI tool to generate HTML and CSS templates for common UI elements",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-template": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
|
+
"start": "node bin/cli.js",
|
|
12
|
+
"create": "node bin/cli.js create",
|
|
13
|
+
"list": "node bin/cli.js list",
|
|
14
|
+
"insert": "node bin/cli.js insert"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"cli",
|
|
18
|
+
"template",
|
|
19
|
+
"html",
|
|
20
|
+
"css",
|
|
21
|
+
"generator",
|
|
22
|
+
"ui-components",
|
|
23
|
+
"html-template",
|
|
24
|
+
"css-template",
|
|
25
|
+
"component-generator",
|
|
26
|
+
"ui-generator",
|
|
27
|
+
"button",
|
|
28
|
+
"card",
|
|
29
|
+
"form",
|
|
30
|
+
"navigation",
|
|
31
|
+
"modal",
|
|
32
|
+
"footer",
|
|
33
|
+
"hero"
|
|
34
|
+
],
|
|
35
|
+
"author": "Ben Shabbat <benshabbat@example.com> (https://github.com/benshabbat)",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/benshabbat/create-template-html-css.git"
|
|
40
|
+
},
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/benshabbat/create-template-html-css/issues"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/benshabbat/create-template-html-css#readme",
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"commander": "^11.1.0",
|
|
47
|
+
"inquirer": "^9.2.12",
|
|
48
|
+
"chalk": "^4.1.2"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/generator.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const fs = require('fs').promises;
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
// Security: Validate component name against whitelist
|
|
5
|
+
const VALID_COMPONENTS = ['button', 'card', 'form', 'navigation', 'modal', 'footer', 'hero'];
|
|
6
|
+
|
|
7
|
+
// Security: Sanitize filename to prevent path traversal
|
|
8
|
+
function sanitizeFilename(filename) {
|
|
9
|
+
// Remove any path separators and parent directory references
|
|
10
|
+
const sanitized = filename.replace(/[\/\\]/g, '').replace(/\.\.+/g, '.');
|
|
11
|
+
|
|
12
|
+
// Additional validation: ensure name contains at least one alphanumeric character
|
|
13
|
+
if (!sanitized || !/[a-zA-Z0-9]/.test(sanitized)) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Remove any remaining dangerous characters
|
|
18
|
+
return sanitized.replace(/[<>:"|?*]/g, '').trim();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function generateTemplate(options) {
|
|
22
|
+
const { component, name, includeJs } = options;
|
|
23
|
+
|
|
24
|
+
// Security: Validate component name
|
|
25
|
+
if (!VALID_COMPONENTS.includes(component)) {
|
|
26
|
+
throw new Error(`Invalid component: ${component}. Must be one of: ${VALID_COMPONENTS.join(', ')}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Security: Sanitize name to prevent path traversal
|
|
30
|
+
const safeName = sanitizeFilename(name);
|
|
31
|
+
if (!safeName || safeName.length === 0) {
|
|
32
|
+
throw new Error('Invalid name provided');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Create output directory
|
|
36
|
+
const outputDir = path.join(process.cwd(), safeName);
|
|
37
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
38
|
+
|
|
39
|
+
// Get template content
|
|
40
|
+
const templateDir = path.join(__dirname, '..', 'templates', component);
|
|
41
|
+
|
|
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));
|
|
45
|
+
|
|
46
|
+
// Copy CSS file
|
|
47
|
+
const cssContent = await fs.readFile(path.join(templateDir, 'style.css'), 'utf-8');
|
|
48
|
+
await fs.writeFile(path.join(outputDir, 'style.css'), cssContent);
|
|
49
|
+
|
|
50
|
+
// Copy JS file if requested
|
|
51
|
+
if (includeJs) {
|
|
52
|
+
try {
|
|
53
|
+
const jsContent = await fs.readFile(path.join(templateDir, 'script.js'), 'utf-8');
|
|
54
|
+
await fs.writeFile(path.join(outputDir, 'script.js'), jsContent);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
// If no JS template exists, create a basic one
|
|
57
|
+
await fs.writeFile(path.join(outputDir, 'script.js'), '// Add your JavaScript here\n');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return outputDir;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = { generateTemplate };
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = { generateTemplate } = require('./generator');
|