@edtools/cli 0.6.1 → 0.7.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.
Files changed (39) hide show
  1. package/dist/adapters/html/index.d.ts +2 -2
  2. package/dist/adapters/html/index.d.ts.map +1 -1
  3. package/dist/adapters/html/index.js +19 -2
  4. package/dist/adapters/html/index.js.map +1 -1
  5. package/dist/adapters/html/templates/base-layout.ejs +173 -0
  6. package/dist/adapters/html/templates/blog-index.html.ejs +170 -101
  7. package/dist/adapters/html/templates/blog-post-enhanced.ejs +655 -0
  8. package/dist/adapters/html/templates/blog-post-new.ejs +612 -0
  9. package/dist/adapters/html/templates/components/footer.ejs +330 -0
  10. package/dist/adapters/html/templates/components/header.ejs +208 -0
  11. package/dist/adapters/html/templates/components/social-share.ejs +202 -0
  12. package/dist/chunk-5N3D47CJ.js +823 -0
  13. package/dist/chunk-TROAGFSZ.js +824 -0
  14. package/dist/chunk-U77FH5BI.js +823 -0
  15. package/dist/cli/commands/config.d.ts +17 -0
  16. package/dist/cli/commands/config.d.ts.map +1 -0
  17. package/dist/cli/commands/config.js +140 -0
  18. package/dist/cli/commands/config.js.map +1 -0
  19. package/dist/cli/commands/generate.d.ts +1 -1
  20. package/dist/cli/commands/generate.d.ts.map +1 -1
  21. package/dist/cli/commands/generate.js +74 -17
  22. package/dist/cli/commands/generate.js.map +1 -1
  23. package/dist/cli/commands/init.d.ts.map +1 -1
  24. package/dist/cli/commands/init.js +114 -0
  25. package/dist/cli/commands/init.js.map +1 -1
  26. package/dist/cli/index.js +567 -265
  27. package/dist/cli/index.js.map +1 -1
  28. package/dist/core/generator.d.ts +4 -1
  29. package/dist/core/generator.d.ts.map +1 -1
  30. package/dist/core/generator.js +114 -3
  31. package/dist/core/generator.js.map +1 -1
  32. package/dist/index.d.ts +87 -3
  33. package/dist/index.js +1 -1
  34. package/dist/types/adapter.d.ts +17 -2
  35. package/dist/types/adapter.d.ts.map +1 -1
  36. package/dist/types/adapter.js.map +1 -1
  37. package/dist/types/content.d.ts +66 -0
  38. package/dist/types/content.d.ts.map +1 -1
  39. package/package.json +2 -2
@@ -0,0 +1,612 @@
1
+ <%
2
+ // Prepare data for base layout
3
+ const pageTitle = metadata.title;
4
+ const pageDescription = metadata.description;
5
+ const pageKeywords = metadata.keywords;
6
+ const pageAuthor = metadata.author;
7
+ const publishDate = metadata.datePublished;
8
+ const canonicalUrl = (blogConfig.websiteUrl || '') + metadata.url;
9
+ const pageType = 'article';
10
+ const pageCategory = metadata.category;
11
+ const pageTags = metadata.tags;
12
+ const ogImage = metadata.ogImage || (blogConfig.defaultOgImage || '');
13
+ const ogImageAlt = metadata.ogImageAlt || metadata.title;
14
+
15
+ // Breadcrumbs data for Schema.org
16
+ const breadcrumbs = [
17
+ { label: 'Home', url: blogConfig.websiteUrl || '/' },
18
+ { label: 'Blog', url: (blogConfig.websiteUrl || '') + '/blog/' },
19
+ { label: metadata.title, url: canonicalUrl }
20
+ ];
21
+
22
+ // Social share data
23
+ const shareData = {
24
+ title: metadata.title,
25
+ description: metadata.description,
26
+ url: canonicalUrl,
27
+ via: blogConfig.social && blogConfig.social.twitter ? blogConfig.social.twitter.replace('https://twitter.com/', '').replace('@', '') : null
28
+ };
29
+
30
+ // Custom styles for blog post
31
+ const customStyles = `
32
+ <style>
33
+ .post-container {
34
+ max-width: 800px;
35
+ margin: 0 auto;
36
+ padding: 2rem 1rem;
37
+ }
38
+
39
+ .post-header {
40
+ margin-bottom: 2rem;
41
+ }
42
+
43
+ .post-meta {
44
+ display: flex;
45
+ align-items: center;
46
+ gap: 1rem;
47
+ flex-wrap: wrap;
48
+ font-size: 0.875rem;
49
+ color: var(--text-light);
50
+ margin-bottom: 1.5rem;
51
+ }
52
+
53
+ .post-meta-item {
54
+ display: flex;
55
+ align-items: center;
56
+ gap: 0.375rem;
57
+ }
58
+
59
+ .post-category {
60
+ display: inline-block;
61
+ padding: 0.25rem 0.75rem;
62
+ background: var(--primary-color);
63
+ color: white;
64
+ border-radius: 9999px;
65
+ font-size: 0.8125rem;
66
+ font-weight: 600;
67
+ text-decoration: none;
68
+ }
69
+
70
+ .post-category:hover {
71
+ opacity: 0.9;
72
+ text-decoration: none;
73
+ }
74
+
75
+ .breadcrumbs {
76
+ display: flex;
77
+ align-items: center;
78
+ gap: 0.5rem;
79
+ font-size: 0.875rem;
80
+ color: var(--text-light);
81
+ margin-bottom: 1.5rem;
82
+ }
83
+
84
+ .breadcrumbs a {
85
+ color: var(--primary-color);
86
+ }
87
+
88
+ .breadcrumbs span {
89
+ color: var(--text-light);
90
+ }
91
+
92
+ h1 {
93
+ font-size: 2.5rem;
94
+ font-weight: 700;
95
+ line-height: 1.2;
96
+ margin-bottom: 1rem;
97
+ color: var(--text-color);
98
+ }
99
+
100
+ .post-intro {
101
+ font-size: 1.125rem;
102
+ color: var(--text-light);
103
+ margin-bottom: 2rem;
104
+ padding-bottom: 2rem;
105
+ border-bottom: 1px solid var(--border-color);
106
+ }
107
+
108
+ /* Table of Contents */
109
+ .table-of-contents {
110
+ background: var(--bg-light);
111
+ border: 1px solid var(--border-color);
112
+ border-radius: 0.5rem;
113
+ padding: 1.5rem;
114
+ margin-bottom: 2rem;
115
+ }
116
+
117
+ .toc-title {
118
+ font-size: 1rem;
119
+ font-weight: 600;
120
+ color: var(--text-color);
121
+ margin-bottom: 1rem;
122
+ }
123
+
124
+ .toc-list {
125
+ list-style: none;
126
+ padding: 0;
127
+ margin: 0;
128
+ }
129
+
130
+ .toc-item {
131
+ margin-bottom: 0.5rem;
132
+ }
133
+
134
+ .toc-item-level-2 {
135
+ padding-left: 0;
136
+ }
137
+
138
+ .toc-item-level-3 {
139
+ padding-left: 1rem;
140
+ }
141
+
142
+ .toc-item-level-4 {
143
+ padding-left: 2rem;
144
+ }
145
+
146
+ .toc-link {
147
+ color: var(--text-color);
148
+ text-decoration: none;
149
+ font-size: 0.9375rem;
150
+ transition: color 0.2s;
151
+ }
152
+
153
+ .toc-link:hover {
154
+ color: var(--primary-color);
155
+ text-decoration: none;
156
+ }
157
+
158
+ /* Post content */
159
+ .post-content h2 {
160
+ font-size: 1.875rem;
161
+ font-weight: 600;
162
+ margin-top: 2.5rem;
163
+ margin-bottom: 1rem;
164
+ color: var(--text-color);
165
+ }
166
+
167
+ .post-content h3 {
168
+ font-size: 1.5rem;
169
+ font-weight: 600;
170
+ margin-top: 2rem;
171
+ margin-bottom: 0.75rem;
172
+ color: var(--text-color);
173
+ }
174
+
175
+ .post-content h4 {
176
+ font-size: 1.25rem;
177
+ font-weight: 600;
178
+ margin-top: 1.5rem;
179
+ margin-bottom: 0.5rem;
180
+ color: var(--text-color);
181
+ }
182
+
183
+ .post-content p {
184
+ margin-bottom: 1rem;
185
+ color: var(--text-color);
186
+ }
187
+
188
+ .post-content section {
189
+ margin-bottom: 2.5rem;
190
+ }
191
+
192
+ /* Comparison table */
193
+ .comparison-table {
194
+ width: 100%;
195
+ border-collapse: collapse;
196
+ margin: 1.5rem 0;
197
+ font-size: 0.9375rem;
198
+ }
199
+
200
+ .comparison-table thead {
201
+ background: var(--bg-light);
202
+ }
203
+
204
+ .comparison-table th,
205
+ .comparison-table td {
206
+ padding: 0.75rem 1rem;
207
+ text-align: left;
208
+ border: 1px solid var(--border-color);
209
+ }
210
+
211
+ .comparison-table th {
212
+ font-weight: 600;
213
+ color: var(--text-color);
214
+ }
215
+
216
+ .comparison-table tbody tr:hover {
217
+ background: var(--bg-light);
218
+ }
219
+
220
+ /* Lists */
221
+ .content-list {
222
+ margin: 1.5rem 0;
223
+ padding-left: 1.5rem;
224
+ }
225
+
226
+ .content-list li {
227
+ margin-bottom: 1rem;
228
+ }
229
+
230
+ .content-list strong {
231
+ color: var(--text-color);
232
+ display: block;
233
+ margin-bottom: 0.25rem;
234
+ }
235
+
236
+ /* Code blocks */
237
+ .code-block {
238
+ margin: 1.5rem 0;
239
+ background: var(--bg-light);
240
+ border: 1px solid var(--border-color);
241
+ border-radius: 0.375rem;
242
+ overflow: hidden;
243
+ }
244
+
245
+ .code-caption {
246
+ padding: 0.5rem 1rem;
247
+ background: #e5e7eb;
248
+ font-size: 0.875rem;
249
+ font-weight: 600;
250
+ border-bottom: 1px solid var(--border-color);
251
+ }
252
+
253
+ .code-block pre {
254
+ padding: 1rem;
255
+ overflow-x: auto;
256
+ }
257
+
258
+ .code-block code {
259
+ font-family: 'Monaco', 'Courier New', monospace;
260
+ font-size: 0.875rem;
261
+ line-height: 1.5;
262
+ }
263
+
264
+ /* Conclusion */
265
+ .post-conclusion {
266
+ margin-top: 3rem;
267
+ padding-top: 2rem;
268
+ border-top: 1px solid var(--border-color);
269
+ }
270
+
271
+ /* CTA */
272
+ .post-cta {
273
+ margin-top: 3rem;
274
+ padding: 2rem;
275
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
276
+ border-radius: 0.5rem;
277
+ text-align: center;
278
+ }
279
+
280
+ .post-cta a {
281
+ display: inline-block;
282
+ padding: 1rem 2rem;
283
+ background: white;
284
+ color: var(--primary-color);
285
+ font-weight: 600;
286
+ font-size: 1.125rem;
287
+ border-radius: 0.375rem;
288
+ transition: transform 0.2s;
289
+ text-decoration: none;
290
+ }
291
+
292
+ .post-cta a:hover {
293
+ transform: translateY(-2px);
294
+ text-decoration: none;
295
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
296
+ }
297
+
298
+ /* Related posts */
299
+ .related-posts {
300
+ margin-top: 4rem;
301
+ padding-top: 2rem;
302
+ border-top: 2px solid var(--border-color);
303
+ }
304
+
305
+ .related-posts h3 {
306
+ margin-top: 0;
307
+ margin-bottom: 1.5rem;
308
+ }
309
+
310
+ .related-posts-grid {
311
+ display: grid;
312
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
313
+ gap: 1.5rem;
314
+ }
315
+
316
+ .related-post-card {
317
+ border: 1px solid var(--border-color);
318
+ border-radius: 0.5rem;
319
+ padding: 1.5rem;
320
+ transition: box-shadow 0.2s;
321
+ }
322
+
323
+ .related-post-card:hover {
324
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
325
+ }
326
+
327
+ .related-post-title {
328
+ font-weight: 600;
329
+ color: var(--text-color);
330
+ margin-bottom: 0.5rem;
331
+ }
332
+
333
+ .related-post-title a {
334
+ color: var(--text-color);
335
+ text-decoration: none;
336
+ }
337
+
338
+ .related-post-title a:hover {
339
+ color: var(--primary-color);
340
+ }
341
+
342
+ .related-post-excerpt {
343
+ color: var(--text-light);
344
+ font-size: 0.875rem;
345
+ }
346
+
347
+ /* Post navigation */
348
+ .post-navigation {
349
+ display: grid;
350
+ grid-template-columns: 1fr 1fr;
351
+ gap: 1.5rem;
352
+ margin-top: 3rem;
353
+ padding-top: 2rem;
354
+ border-top: 1px solid var(--border-color);
355
+ }
356
+
357
+ .post-nav-link {
358
+ display: block;
359
+ padding: 1.5rem;
360
+ border: 1px solid var(--border-color);
361
+ border-radius: 0.5rem;
362
+ text-decoration: none;
363
+ transition: all 0.2s;
364
+ }
365
+
366
+ .post-nav-link:hover {
367
+ border-color: var(--primary-color);
368
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
369
+ text-decoration: none;
370
+ }
371
+
372
+ .post-nav-link.prev {
373
+ text-align: left;
374
+ }
375
+
376
+ .post-nav-link.next {
377
+ text-align: right;
378
+ }
379
+
380
+ .post-nav-label {
381
+ font-size: 0.8125rem;
382
+ text-transform: uppercase;
383
+ font-weight: 600;
384
+ color: var(--text-light);
385
+ letter-spacing: 0.05em;
386
+ margin-bottom: 0.5rem;
387
+ }
388
+
389
+ .post-nav-title {
390
+ color: var(--text-color);
391
+ font-weight: 600;
392
+ font-size: 1rem;
393
+ }
394
+
395
+ /* Tags */
396
+ .post-tags {
397
+ display: flex;
398
+ flex-wrap: wrap;
399
+ gap: 0.5rem;
400
+ margin-top: 2rem;
401
+ }
402
+
403
+ .post-tag {
404
+ display: inline-block;
405
+ padding: 0.375rem 0.75rem;
406
+ background: var(--bg-light);
407
+ color: var(--text-color);
408
+ border: 1px solid var(--border-color);
409
+ border-radius: 0.25rem;
410
+ font-size: 0.875rem;
411
+ text-decoration: none;
412
+ transition: all 0.2s;
413
+ }
414
+
415
+ .post-tag:hover {
416
+ border-color: var(--primary-color);
417
+ color: var(--primary-color);
418
+ text-decoration: none;
419
+ }
420
+
421
+ /* Mobile responsive */
422
+ @media (max-width: 768px) {
423
+ h1 {
424
+ font-size: 2rem;
425
+ }
426
+
427
+ .post-navigation {
428
+ grid-template-columns: 1fr;
429
+ }
430
+
431
+ .post-nav-link.next {
432
+ text-align: left;
433
+ }
434
+
435
+ .related-posts-grid {
436
+ grid-template-columns: 1fr;
437
+ }
438
+ }
439
+ </style>
440
+ `;
441
+
442
+ // Render content block
443
+ const content = `
444
+ <article class="post-container">
445
+ <!-- Breadcrumbs -->
446
+ <nav class="breadcrumbs" aria-label="Breadcrumb">
447
+ <a href="${blogConfig.websiteUrl || '/'}">Home</a>
448
+ <span>/</span>
449
+ <a href="${(blogConfig.websiteUrl || '') + '/blog/'}">Blog</a>
450
+ <% if (metadata.category) { %>
451
+ <span>/</span>
452
+ <a href="/blog/category/${metadata.category.toLowerCase().replace(/\\s+/g, '-')}/">${metadata.category}</a>
453
+ <% } %>
454
+ <span>/</span>
455
+ <span>${metadata.title}</span>
456
+ </nav>
457
+
458
+ <header class="post-header">
459
+ <h1>${metadata.title}</h1>
460
+
461
+ <div class="post-meta">
462
+ <% if (metadata.category) { %>
463
+ <a href="/blog/category/${metadata.category.toLowerCase().replace(/\\s+/g, '-')}/" class="post-category">
464
+ ${metadata.category}
465
+ </a>
466
+ <% } %>
467
+ <div class="post-meta-item">
468
+ <svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
469
+ <circle cx="12" cy="12" r="10"></circle>
470
+ <polyline points="12 6 12 12 16 14"></polyline>
471
+ </svg>
472
+ <span>${metadata.readTime}</span>
473
+ </div>
474
+ <div class="post-meta-item">
475
+ <svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
476
+ <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
477
+ <line x1="16" y1="2" x2="16" y2="6"></line>
478
+ <line x1="8" y1="2" x2="8" y2="6"></line>
479
+ <line x1="3" y1="10" x2="21" y2="10"></line>
480
+ </svg>
481
+ <time datetime="${metadata.datePublished}">${new Date(metadata.datePublished).toLocaleDateString('es-ES', { year: 'numeric', month: 'long', day: 'numeric' })}</time>
482
+ </div>
483
+ <% if (metadata.author) { %>
484
+ <div class="post-meta-item">
485
+ <svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
486
+ <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
487
+ <circle cx="12" cy="7" r="4"></circle>
488
+ </svg>
489
+ <span>${metadata.author}</span>
490
+ </div>
491
+ <% } %>
492
+ </div>
493
+ </header>
494
+
495
+ <div class="post-intro">
496
+ <%- intro %>
497
+ </div>
498
+
499
+ <% if (tableOfContents && tableOfContents.length > 0) { %>
500
+ <!-- Table of Contents -->
501
+ <nav class="table-of-contents" aria-label="Table of Contents">
502
+ <div class="toc-title">Table of Contents</div>
503
+ <ul class="toc-list">
504
+ <% tableOfContents.forEach(item => { %>
505
+ <li class="toc-item toc-item-level-${item.level}">
506
+ <a href="#${item.id}" class="toc-link">${item.text}</a>
507
+ </li>
508
+ <% }) %>
509
+ </ul>
510
+ </nav>
511
+ <% } %>
512
+
513
+ <div class="post-content">
514
+ <% sections.forEach(section => { %>
515
+ <section id="${section.heading.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '')}">
516
+ <h${section.level}>${section.heading}</h${section.level}>
517
+ <%- section.content %>
518
+ </section>
519
+ <% }) %>
520
+ </div>
521
+
522
+ <div class="post-conclusion">
523
+ <%- conclusion %>
524
+ </div>
525
+
526
+ <!-- Tags -->
527
+ <% if (metadata.tags && metadata.tags.length > 0) { %>
528
+ <div class="post-tags">
529
+ <% metadata.tags.forEach(tag => { %>
530
+ <a href="/blog/tag/${tag.toLowerCase().replace(/\\s+/g, '-')}/" class="post-tag">#${tag}</a>
531
+ <% }) %>
532
+ </div>
533
+ <% } %>
534
+
535
+ <!-- Social Share -->
536
+ <%- include('components/social-share', { shareData }) %>
537
+
538
+ <div class="post-cta">
539
+ <a href="${cta.url}">${cta.text}</a>
540
+ </div>
541
+
542
+ <% if (relatedPosts && relatedPosts.length > 0) { %>
543
+ <!-- Related Posts -->
544
+ <div class="related-posts">
545
+ <h3>Related Articles</h3>
546
+ <div class="related-posts-grid">
547
+ <% relatedPosts.forEach(post => { %>
548
+ <div class="related-post-card">
549
+ <div class="related-post-title">
550
+ <a href="${post.url}">${post.title}</a>
551
+ </div>
552
+ <% if (post.excerpt) { %>
553
+ <p class="related-post-excerpt">${post.excerpt}</p>
554
+ <% } %>
555
+ </div>
556
+ <% }) %>
557
+ </div>
558
+ </div>
559
+ <% } %>
560
+
561
+ <% if (prevPost || nextPost) { %>
562
+ <!-- Post Navigation -->
563
+ <nav class="post-navigation" aria-label="Post navigation">
564
+ <% if (prevPost) { %>
565
+ <a href="${prevPost.url}" class="post-nav-link prev" rel="prev">
566
+ <div class="post-nav-label">← Previous</div>
567
+ <div class="post-nav-title">${prevPost.title}</div>
568
+ </a>
569
+ <% } else { %>
570
+ <div></div>
571
+ <% } %>
572
+
573
+ <% if (nextPost) { %>
574
+ <a href="${nextPost.url}" class="post-nav-link next" rel="next">
575
+ <div class="post-nav-label">Next →</div>
576
+ <div class="post-nav-title">${nextPost.title}</div>
577
+ </a>
578
+ <% } %>
579
+ </nav>
580
+ <% } %>
581
+ </article>
582
+
583
+ <!-- AI-friendly metadata in comments for LLM parsing -->
584
+ <!--
585
+ METADATA:
586
+ - Title: ${metadata.title}
587
+ - Category: ${metadata.category}
588
+ - Keywords: ${metadata.keywords.join(', ')}
589
+ - Published: ${metadata.datePublished}
590
+ - SEO Score: ${seoScore}/100
591
+ -->
592
+ `;
593
+
594
+ %>
595
+ <%- include('base-layout', {
596
+ blogConfig,
597
+ pageTitle,
598
+ pageDescription,
599
+ pageKeywords,
600
+ pageAuthor,
601
+ publishDate,
602
+ canonicalUrl,
603
+ pageType,
604
+ pageCategory,
605
+ pageTags,
606
+ ogImage,
607
+ ogImageAlt,
608
+ breadcrumbs,
609
+ schemaOrg,
610
+ customStyles,
611
+ content
612
+ }) %>