inkpen 0.7.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.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.rubocop.yml +8 -0
  4. data/.yardopts +11 -0
  5. data/CLAUDE.md +141 -0
  6. data/README.md +409 -0
  7. data/Rakefile +19 -0
  8. data/app/assets/javascripts/inkpen/controllers/editor_controller.js +2050 -0
  9. data/app/assets/javascripts/inkpen/controllers/sticky_toolbar_controller.js +667 -0
  10. data/app/assets/javascripts/inkpen/controllers/toolbar_controller.js +693 -0
  11. data/app/assets/javascripts/inkpen/export/html.js +637 -0
  12. data/app/assets/javascripts/inkpen/export/index.js +30 -0
  13. data/app/assets/javascripts/inkpen/export/markdown.js +697 -0
  14. data/app/assets/javascripts/inkpen/export/pdf.js +372 -0
  15. data/app/assets/javascripts/inkpen/extensions/advanced_table.js +640 -0
  16. data/app/assets/javascripts/inkpen/extensions/block_commands.js +300 -0
  17. data/app/assets/javascripts/inkpen/extensions/block_gutter.js +338 -0
  18. data/app/assets/javascripts/inkpen/extensions/callout.js +303 -0
  19. data/app/assets/javascripts/inkpen/extensions/columns.js +403 -0
  20. data/app/assets/javascripts/inkpen/extensions/database.js +990 -0
  21. data/app/assets/javascripts/inkpen/extensions/document_section.js +352 -0
  22. data/app/assets/javascripts/inkpen/extensions/drag_handle.js +407 -0
  23. data/app/assets/javascripts/inkpen/extensions/embed.js +629 -0
  24. data/app/assets/javascripts/inkpen/extensions/enhanced_image.js +566 -0
  25. data/app/assets/javascripts/inkpen/extensions/export_commands.js +271 -0
  26. data/app/assets/javascripts/inkpen/extensions/file_attachment.js +593 -0
  27. data/app/assets/javascripts/inkpen/extensions/inkpen_table/index.js +58 -0
  28. data/app/assets/javascripts/inkpen/extensions/inkpen_table/inkpen_table.js +638 -0
  29. data/app/assets/javascripts/inkpen/extensions/inkpen_table/inkpen_table_cell.js +100 -0
  30. data/app/assets/javascripts/inkpen/extensions/inkpen_table/inkpen_table_header.js +100 -0
  31. data/app/assets/javascripts/inkpen/extensions/inkpen_table/table_constants.js +152 -0
  32. data/app/assets/javascripts/inkpen/extensions/inkpen_table/table_helpers.js +254 -0
  33. data/app/assets/javascripts/inkpen/extensions/inkpen_table/table_menu.js +282 -0
  34. data/app/assets/javascripts/inkpen/extensions/preformatted.js +239 -0
  35. data/app/assets/javascripts/inkpen/extensions/section.js +281 -0
  36. data/app/assets/javascripts/inkpen/extensions/section_title.js +126 -0
  37. data/app/assets/javascripts/inkpen/extensions/slash_commands.js +439 -0
  38. data/app/assets/javascripts/inkpen/extensions/table_of_contents.js +474 -0
  39. data/app/assets/javascripts/inkpen/extensions/toggle_block.js +332 -0
  40. data/app/assets/javascripts/inkpen/index.js +87 -0
  41. data/app/assets/stylesheets/inkpen/advanced_table.css +514 -0
  42. data/app/assets/stylesheets/inkpen/animations.css +626 -0
  43. data/app/assets/stylesheets/inkpen/block_gutter.css +265 -0
  44. data/app/assets/stylesheets/inkpen/callout.css +359 -0
  45. data/app/assets/stylesheets/inkpen/columns.css +314 -0
  46. data/app/assets/stylesheets/inkpen/database.css +658 -0
  47. data/app/assets/stylesheets/inkpen/document_section.css +305 -0
  48. data/app/assets/stylesheets/inkpen/drag_drop.css +220 -0
  49. data/app/assets/stylesheets/inkpen/editor.css +652 -0
  50. data/app/assets/stylesheets/inkpen/embed.css +468 -0
  51. data/app/assets/stylesheets/inkpen/enhanced_image.css +453 -0
  52. data/app/assets/stylesheets/inkpen/export.css +499 -0
  53. data/app/assets/stylesheets/inkpen/file_attachment.css +347 -0
  54. data/app/assets/stylesheets/inkpen/footnotes.css +136 -0
  55. data/app/assets/stylesheets/inkpen/inkpen_table.css +608 -0
  56. data/app/assets/stylesheets/inkpen/preformatted.css +215 -0
  57. data/app/assets/stylesheets/inkpen/search_replace.css +58 -0
  58. data/app/assets/stylesheets/inkpen/section.css +236 -0
  59. data/app/assets/stylesheets/inkpen/slash_menu.css +252 -0
  60. data/app/assets/stylesheets/inkpen/sticky_toolbar.css +314 -0
  61. data/app/assets/stylesheets/inkpen/toc.css +386 -0
  62. data/app/assets/stylesheets/inkpen/toggle.css +260 -0
  63. data/app/helpers/inkpen/editor_helper.rb +114 -0
  64. data/app/views/inkpen/_editor.html.erb +139 -0
  65. data/config/importmap.rb +170 -0
  66. data/docs/.DS_Store +0 -0
  67. data/docs/CHANGELOG.md +571 -0
  68. data/docs/FEATURES.md +436 -0
  69. data/docs/ROADMAP.md +3029 -0
  70. data/docs/VISION.md +235 -0
  71. data/docs/extensions/INKPEN_TABLE.md +482 -0
  72. data/docs/thinking/CORRECTED_NO_VUE.md +756 -0
  73. data/docs/thinking/EXECUTIVE_SUMMARY.md +403 -0
  74. data/docs/thinking/INKPEN_CODE_SAMPLES.md +1479 -0
  75. data/docs/thinking/INKPEN_MASTER_GUIDE.md +891 -0
  76. data/docs/thinking/README_START_HERE.md +341 -0
  77. data/lib/inkpen/configuration.rb +175 -0
  78. data/lib/inkpen/editor.rb +204 -0
  79. data/lib/inkpen/engine.rb +32 -0
  80. data/lib/inkpen/extensions/base.rb +109 -0
  81. data/lib/inkpen/extensions/code_block_syntax.rb +177 -0
  82. data/lib/inkpen/extensions/document_section.rb +111 -0
  83. data/lib/inkpen/extensions/forced_document.rb +183 -0
  84. data/lib/inkpen/extensions/mention.rb +155 -0
  85. data/lib/inkpen/extensions/preformatted.rb +111 -0
  86. data/lib/inkpen/extensions/section.rb +139 -0
  87. data/lib/inkpen/extensions/slash_commands.rb +100 -0
  88. data/lib/inkpen/extensions/table.rb +182 -0
  89. data/lib/inkpen/extensions/task_list.rb +145 -0
  90. data/lib/inkpen/sticky_toolbar.rb +157 -0
  91. data/lib/inkpen/toolbar.rb +145 -0
  92. data/lib/inkpen/version.rb +5 -0
  93. data/lib/inkpen.rb +101 -0
  94. data/sig/inkpen.rbs +4 -0
  95. metadata +165 -0
@@ -0,0 +1,637 @@
1
+ /**
2
+ * HTML Export
3
+ *
4
+ * Generates clean, semantic HTML from TipTap editor content.
5
+ * Supports optional styling, class prefixes, and full document wrapping.
6
+ */
7
+
8
+ /**
9
+ * Export editor document to HTML
10
+ *
11
+ * @param {Editor} editor - TipTap editor instance
12
+ * @param {Object} options - Export options
13
+ * @returns {string} HTML content
14
+ */
15
+ export function exportToHTML(editor, options = {}) {
16
+ const {
17
+ includeStyles = true,
18
+ inlineStyles = false,
19
+ classPrefix = "inkpen-",
20
+ embedImages = false,
21
+ includeWrapper = true,
22
+ title = "Document",
23
+ theme = "light"
24
+ } = options
25
+
26
+ // Get raw HTML from editor
27
+ let content = editor.getHTML()
28
+
29
+ // Add class prefixes if specified
30
+ if (classPrefix && classPrefix !== "inkpen-") {
31
+ content = addClassPrefix(content, classPrefix)
32
+ }
33
+
34
+ // Embed images as base64 if requested
35
+ if (embedImages) {
36
+ content = embedImagesAsBase64(content)
37
+ }
38
+
39
+ // Wrap in full HTML document
40
+ if (includeWrapper) {
41
+ return wrapInDocument(content, {
42
+ title,
43
+ includeStyles,
44
+ inlineStyles,
45
+ classPrefix,
46
+ theme
47
+ })
48
+ }
49
+
50
+ // Return content with optional style tag
51
+ if (includeStyles && inlineStyles) {
52
+ return `<style>${getExportStyles(classPrefix)}</style>\n${content}`
53
+ }
54
+
55
+ return content
56
+ }
57
+
58
+ /**
59
+ * Wrap content in a full HTML document
60
+ */
61
+ function wrapInDocument(content, options) {
62
+ const { title, includeStyles, inlineStyles, classPrefix, theme } = options
63
+
64
+ let styleBlock = ""
65
+ if (includeStyles) {
66
+ if (inlineStyles) {
67
+ styleBlock = ` <style>\n${getExportStyles(classPrefix, 4)}\n </style>`
68
+ } else {
69
+ styleBlock = ` <link rel="stylesheet" href="inkpen-export.css">`
70
+ }
71
+ }
72
+
73
+ return `<!DOCTYPE html>
74
+ <html lang="en" data-theme="${theme}">
75
+ <head>
76
+ <meta charset="UTF-8">
77
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
78
+ <title>${escapeHtml(title)}</title>
79
+ ${styleBlock}
80
+ </head>
81
+ <body>
82
+ <article class="${classPrefix}document">
83
+ ${indentContent(content, 4)}
84
+ </article>
85
+ </body>
86
+ </html>`
87
+ }
88
+
89
+ /**
90
+ * Get export styles
91
+ */
92
+ function getExportStyles(prefix = "inkpen-", indent = 0) {
93
+ const pad = " ".repeat(indent)
94
+
95
+ const styles = `
96
+ /* Base document styles */
97
+ .${prefix}document {
98
+ max-width: 680px;
99
+ margin: 0 auto;
100
+ padding: 2rem;
101
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
102
+ font-size: 16px;
103
+ line-height: 1.6;
104
+ color: #1a1a1a;
105
+ background: #ffffff;
106
+ }
107
+
108
+ /* Typography */
109
+ .${prefix}document h1 {
110
+ font-size: 2rem;
111
+ font-weight: 700;
112
+ margin: 2rem 0 1rem;
113
+ line-height: 1.2;
114
+ }
115
+
116
+ .${prefix}document h2 {
117
+ font-size: 1.5rem;
118
+ font-weight: 600;
119
+ margin: 1.75rem 0 0.75rem;
120
+ line-height: 1.3;
121
+ }
122
+
123
+ .${prefix}document h3 {
124
+ font-size: 1.25rem;
125
+ font-weight: 600;
126
+ margin: 1.5rem 0 0.5rem;
127
+ line-height: 1.4;
128
+ }
129
+
130
+ .${prefix}document h4 {
131
+ font-size: 1rem;
132
+ font-weight: 600;
133
+ margin: 1.25rem 0 0.5rem;
134
+ }
135
+
136
+ .${prefix}document p {
137
+ margin: 0 0 1rem;
138
+ }
139
+
140
+ .${prefix}document a {
141
+ color: #2563eb;
142
+ text-decoration: underline;
143
+ }
144
+
145
+ .${prefix}document a:hover {
146
+ color: #1d4ed8;
147
+ }
148
+
149
+ /* Lists */
150
+ .${prefix}document ul,
151
+ .${prefix}document ol {
152
+ margin: 0 0 1rem;
153
+ padding-left: 1.5rem;
154
+ }
155
+
156
+ .${prefix}document li {
157
+ margin: 0.25rem 0;
158
+ }
159
+
160
+ .${prefix}document li > ul,
161
+ .${prefix}document li > ol {
162
+ margin: 0.25rem 0;
163
+ }
164
+
165
+ /* Task list */
166
+ .${prefix}document ul[data-type="taskList"] {
167
+ list-style: none;
168
+ padding-left: 0;
169
+ }
170
+
171
+ .${prefix}document ul[data-type="taskList"] li {
172
+ display: flex;
173
+ align-items: flex-start;
174
+ gap: 0.5rem;
175
+ }
176
+
177
+ .${prefix}document ul[data-type="taskList"] input[type="checkbox"] {
178
+ margin-top: 0.25rem;
179
+ }
180
+
181
+ /* Blockquote */
182
+ .${prefix}document blockquote {
183
+ margin: 1rem 0;
184
+ padding: 0.75rem 1rem;
185
+ border-left: 3px solid #e5e7eb;
186
+ color: #4b5563;
187
+ background: #f9fafb;
188
+ }
189
+
190
+ .${prefix}document blockquote p:last-child {
191
+ margin-bottom: 0;
192
+ }
193
+
194
+ /* Code */
195
+ .${prefix}document code {
196
+ background: #f3f4f6;
197
+ padding: 0.125rem 0.375rem;
198
+ border-radius: 0.25rem;
199
+ font-size: 0.875em;
200
+ font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
201
+ }
202
+
203
+ .${prefix}document pre {
204
+ background: #1f2937;
205
+ color: #f9fafb;
206
+ padding: 1rem;
207
+ border-radius: 0.5rem;
208
+ overflow-x: auto;
209
+ margin: 1rem 0;
210
+ }
211
+
212
+ .${prefix}document pre code {
213
+ background: transparent;
214
+ padding: 0;
215
+ font-size: 0.875rem;
216
+ color: inherit;
217
+ }
218
+
219
+ /* Horizontal rule */
220
+ .${prefix}document hr {
221
+ border: none;
222
+ border-top: 1px solid #e5e7eb;
223
+ margin: 2rem 0;
224
+ }
225
+
226
+ /* Images */
227
+ .${prefix}document img {
228
+ max-width: 100%;
229
+ height: auto;
230
+ border-radius: 0.5rem;
231
+ }
232
+
233
+ .${prefix}document figure {
234
+ margin: 1.5rem 0;
235
+ text-align: center;
236
+ }
237
+
238
+ .${prefix}document figcaption {
239
+ margin-top: 0.5rem;
240
+ font-size: 0.875rem;
241
+ color: #6b7280;
242
+ }
243
+
244
+ /* Tables */
245
+ .${prefix}document table {
246
+ width: 100%;
247
+ border-collapse: collapse;
248
+ margin: 1rem 0;
249
+ }
250
+
251
+ .${prefix}document th,
252
+ .${prefix}document td {
253
+ border: 1px solid #e5e7eb;
254
+ padding: 0.5rem 0.75rem;
255
+ text-align: left;
256
+ }
257
+
258
+ .${prefix}document th {
259
+ background: #f9fafb;
260
+ font-weight: 600;
261
+ }
262
+
263
+ .${prefix}document tr:nth-child(even) td {
264
+ background: #fafafa;
265
+ }
266
+
267
+ /* Callouts */
268
+ .${prefix}callout {
269
+ padding: 1rem;
270
+ margin: 1rem 0;
271
+ border-radius: 0.5rem;
272
+ border-left: 4px solid;
273
+ }
274
+
275
+ .${prefix}callout--info {
276
+ background: #eff6ff;
277
+ border-color: #3b82f6;
278
+ }
279
+
280
+ .${prefix}callout--warning {
281
+ background: #fffbeb;
282
+ border-color: #f59e0b;
283
+ }
284
+
285
+ .${prefix}callout--tip {
286
+ background: #f0fdf4;
287
+ border-color: #22c55e;
288
+ }
289
+
290
+ .${prefix}callout--note {
291
+ background: #f5f5f5;
292
+ border-color: #737373;
293
+ }
294
+
295
+ .${prefix}callout--success {
296
+ background: #f0fdf4;
297
+ border-color: #22c55e;
298
+ }
299
+
300
+ .${prefix}callout--error {
301
+ background: #fef2f2;
302
+ border-color: #ef4444;
303
+ }
304
+
305
+ /* Toggle/Details */
306
+ .${prefix}document details {
307
+ margin: 1rem 0;
308
+ border: 1px solid #e5e7eb;
309
+ border-radius: 0.5rem;
310
+ }
311
+
312
+ .${prefix}document summary {
313
+ padding: 0.75rem 1rem;
314
+ cursor: pointer;
315
+ font-weight: 500;
316
+ background: #f9fafb;
317
+ border-radius: 0.5rem 0.5rem 0 0;
318
+ }
319
+
320
+ .${prefix}document details[open] summary {
321
+ border-bottom: 1px solid #e5e7eb;
322
+ }
323
+
324
+ .${prefix}document details > *:not(summary) {
325
+ padding: 1rem;
326
+ }
327
+
328
+ /* Columns */
329
+ .${prefix}columns {
330
+ display: grid;
331
+ gap: 1.5rem;
332
+ margin: 1rem 0;
333
+ }
334
+
335
+ .${prefix}columns--2 { grid-template-columns: repeat(2, 1fr); }
336
+ .${prefix}columns--3 { grid-template-columns: repeat(3, 1fr); }
337
+ .${prefix}columns--4 { grid-template-columns: repeat(4, 1fr); }
338
+
339
+ @media (max-width: 640px) {
340
+ .${prefix}columns {
341
+ grid-template-columns: 1fr !important;
342
+ }
343
+ }
344
+
345
+ /* File attachment */
346
+ .${prefix}file {
347
+ display: flex;
348
+ align-items: center;
349
+ gap: 0.75rem;
350
+ padding: 0.75rem 1rem;
351
+ background: #f9fafb;
352
+ border: 1px solid #e5e7eb;
353
+ border-radius: 0.5rem;
354
+ margin: 1rem 0;
355
+ text-decoration: none;
356
+ color: inherit;
357
+ }
358
+
359
+ .${prefix}file:hover {
360
+ background: #f3f4f6;
361
+ }
362
+
363
+ .${prefix}file__icon {
364
+ font-size: 1.5rem;
365
+ }
366
+
367
+ .${prefix}file__info {
368
+ flex: 1;
369
+ }
370
+
371
+ .${prefix}file__name {
372
+ font-weight: 500;
373
+ }
374
+
375
+ .${prefix}file__size {
376
+ font-size: 0.75rem;
377
+ color: #6b7280;
378
+ }
379
+
380
+ /* Embed */
381
+ .${prefix}embed {
382
+ margin: 1.5rem 0;
383
+ }
384
+
385
+ .${prefix}embed iframe {
386
+ width: 100%;
387
+ border: none;
388
+ border-radius: 0.5rem;
389
+ }
390
+
391
+ /* Table of Contents */
392
+ .${prefix}toc {
393
+ padding: 1rem 1.5rem;
394
+ background: #f9fafb;
395
+ border: 1px solid #e5e7eb;
396
+ border-radius: 0.5rem;
397
+ margin: 1.5rem 0;
398
+ }
399
+
400
+ .${prefix}toc__title {
401
+ font-weight: 600;
402
+ font-size: 0.875rem;
403
+ text-transform: uppercase;
404
+ letter-spacing: 0.05em;
405
+ color: #6b7280;
406
+ margin-bottom: 0.75rem;
407
+ }
408
+
409
+ .${prefix}toc__list {
410
+ margin: 0;
411
+ padding-left: 1.25rem;
412
+ }
413
+
414
+ .${prefix}toc__item {
415
+ padding: 0.25rem 0;
416
+ }
417
+
418
+ .${prefix}toc__item a {
419
+ color: inherit;
420
+ text-decoration: none;
421
+ }
422
+
423
+ .${prefix}toc__item a:hover {
424
+ color: #2563eb;
425
+ }
426
+
427
+ /* Database */
428
+ .${prefix}database {
429
+ margin: 1.5rem 0;
430
+ border: 1px solid #e5e7eb;
431
+ border-radius: 0.5rem;
432
+ overflow: hidden;
433
+ }
434
+
435
+ .${prefix}database__header {
436
+ padding: 0.75rem 1rem;
437
+ background: #f9fafb;
438
+ border-bottom: 1px solid #e5e7eb;
439
+ }
440
+
441
+ .${prefix}database__title {
442
+ font-weight: 600;
443
+ }
444
+
445
+ /* Marks */
446
+ .${prefix}document mark,
447
+ .${prefix}highlight {
448
+ background: #fef08a;
449
+ padding: 0.125rem 0;
450
+ }
451
+
452
+ .${prefix}document u {
453
+ text-decoration: underline;
454
+ }
455
+
456
+ .${prefix}document s {
457
+ text-decoration: line-through;
458
+ }
459
+
460
+ .${prefix}document sub {
461
+ font-size: 0.75em;
462
+ vertical-align: sub;
463
+ }
464
+
465
+ .${prefix}document sup {
466
+ font-size: 0.75em;
467
+ vertical-align: super;
468
+ }
469
+
470
+ /* Dark mode */
471
+ @media (prefers-color-scheme: dark) {
472
+ [data-theme="auto"] .${prefix}document {
473
+ background: #111827;
474
+ color: #f9fafb;
475
+ }
476
+
477
+ [data-theme="auto"] .${prefix}document a {
478
+ color: #60a5fa;
479
+ }
480
+
481
+ [data-theme="auto"] .${prefix}document blockquote {
482
+ background: #1f2937;
483
+ border-color: #374151;
484
+ color: #9ca3af;
485
+ }
486
+
487
+ [data-theme="auto"] .${prefix}document code {
488
+ background: #374151;
489
+ }
490
+
491
+ [data-theme="auto"] .${prefix}document th,
492
+ [data-theme="auto"] .${prefix}document summary {
493
+ background: #1f2937;
494
+ }
495
+
496
+ [data-theme="auto"] .${prefix}document th,
497
+ [data-theme="auto"] .${prefix}document td {
498
+ border-color: #374151;
499
+ }
500
+ }
501
+
502
+ [data-theme="dark"] .${prefix}document {
503
+ background: #111827;
504
+ color: #f9fafb;
505
+ }
506
+
507
+ [data-theme="dark"] .${prefix}document a {
508
+ color: #60a5fa;
509
+ }
510
+
511
+ [data-theme="dark"] .${prefix}document blockquote {
512
+ background: #1f2937;
513
+ border-color: #374151;
514
+ color: #9ca3af;
515
+ }
516
+
517
+ [data-theme="dark"] .${prefix}document code {
518
+ background: #374151;
519
+ }
520
+
521
+ /* Print styles */
522
+ @media print {
523
+ .${prefix}document {
524
+ max-width: none;
525
+ padding: 0;
526
+ font-size: 12pt;
527
+ }
528
+
529
+ .${prefix}document a {
530
+ color: inherit;
531
+ text-decoration: underline;
532
+ }
533
+
534
+ .${prefix}document pre {
535
+ white-space: pre-wrap;
536
+ word-wrap: break-word;
537
+ }
538
+
539
+ .${prefix}document img {
540
+ max-width: 100%;
541
+ page-break-inside: avoid;
542
+ }
543
+
544
+ .${prefix}document table {
545
+ page-break-inside: avoid;
546
+ }
547
+
548
+ .${prefix}document h1, .${prefix}document h2, .${prefix}document h3 {
549
+ page-break-after: avoid;
550
+ }
551
+ }
552
+ `
553
+
554
+ // Add indent to each line
555
+ return styles
556
+ .split("\n")
557
+ .map(line => pad + line)
558
+ .join("\n")
559
+ .trim()
560
+ }
561
+
562
+ /**
563
+ * Add class prefix to HTML content
564
+ */
565
+ function addClassPrefix(html, prefix) {
566
+ // Replace inkpen- with custom prefix
567
+ return html.replace(/inkpen-/g, prefix)
568
+ }
569
+
570
+ /**
571
+ * Embed images as base64
572
+ */
573
+ function embedImagesAsBase64(html) {
574
+ // This would require async image loading in practice
575
+ // For now, return unchanged (implement with canvas if needed)
576
+ return html
577
+ }
578
+
579
+ /**
580
+ * Indent content for prettier output
581
+ */
582
+ function indentContent(content, spaces) {
583
+ const pad = " ".repeat(spaces)
584
+ return content
585
+ .split("\n")
586
+ .map(line => line.trim() ? pad + line : "")
587
+ .join("\n")
588
+ }
589
+
590
+ /**
591
+ * Escape HTML entities
592
+ */
593
+ function escapeHtml(text) {
594
+ const map = {
595
+ "&": "&amp;",
596
+ "<": "&lt;",
597
+ ">": "&gt;",
598
+ '"': "&quot;",
599
+ "'": "&#039;"
600
+ }
601
+ return text.replace(/[&<>"']/g, char => map[char])
602
+ }
603
+
604
+ /**
605
+ * Download HTML as file
606
+ */
607
+ export function downloadHTML(content, filename = "document.html") {
608
+ const blob = new Blob([content], { type: "text/html;charset=utf-8" })
609
+ const url = URL.createObjectURL(blob)
610
+ const link = document.createElement("a")
611
+ link.href = url
612
+ link.download = filename
613
+ document.body.appendChild(link)
614
+ link.click()
615
+ document.body.removeChild(link)
616
+ URL.revokeObjectURL(url)
617
+ }
618
+
619
+ /**
620
+ * Copy HTML to clipboard
621
+ */
622
+ export async function copyHTMLToClipboard(content) {
623
+ try {
624
+ await navigator.clipboard.writeText(content)
625
+ return true
626
+ } catch (err) {
627
+ console.error("Failed to copy HTML:", err)
628
+ return false
629
+ }
630
+ }
631
+
632
+ /**
633
+ * Get standalone stylesheet content
634
+ */
635
+ export function getExportStylesheet(prefix = "inkpen-") {
636
+ return getExportStyles(prefix, 0)
637
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Inkpen Export Module
3
+ *
4
+ * Provides export functionality for Markdown, HTML, and PDF formats.
5
+ */
6
+
7
+ // Markdown export/import
8
+ export {
9
+ exportToMarkdown,
10
+ importFromMarkdown,
11
+ downloadMarkdown,
12
+ copyMarkdownToClipboard
13
+ } from "inkpen/export/markdown"
14
+
15
+ // HTML export
16
+ export {
17
+ exportToHTML,
18
+ downloadHTML,
19
+ copyHTMLToClipboard,
20
+ getExportStylesheet
21
+ } from "inkpen/export/html"
22
+
23
+ // PDF export
24
+ export {
25
+ exportToPDF,
26
+ loadHtml2Pdf,
27
+ isPDFExportAvailable,
28
+ getPageSizes,
29
+ getDefaultPDFOptions
30
+ } from "inkpen/export/pdf"