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,271 @@
1
+ import { Extension } from "@tiptap/core"
2
+ import {
3
+ exportToMarkdown,
4
+ downloadMarkdown,
5
+ copyMarkdownToClipboard,
6
+ exportToHTML,
7
+ downloadHTML,
8
+ copyHTMLToClipboard,
9
+ exportToPDF
10
+ } from "inkpen/export"
11
+
12
+ /**
13
+ * Export Commands Extension for TipTap
14
+ *
15
+ * Adds keyboard shortcuts and commands for exporting editor content
16
+ * to Markdown, HTML, and PDF formats.
17
+ *
18
+ * Follows Fizzy patterns:
19
+ * - Section comments for organization
20
+ * - Clean command API
21
+ * - Event-driven callbacks
22
+ *
23
+ * Keyboard Shortcuts:
24
+ * - Cmd+Alt+M: Download as Markdown
25
+ * - Cmd+Alt+H: Download as HTML
26
+ * - Cmd+Alt+P: Download as PDF
27
+ * - Cmd+Alt+C: Copy as Markdown
28
+ * - Cmd+Alt+Shift+C: Copy as HTML
29
+ *
30
+ * @example
31
+ * editor.commands.downloadMarkdown()
32
+ * editor.commands.downloadHTML({ includeStyles: true })
33
+ * editor.commands.downloadPDF({ pageSize: 'letter' })
34
+ *
35
+ * @since 0.7.0
36
+ */
37
+ export const ExportCommands = Extension.create({
38
+ name: "exportCommands",
39
+
40
+ // Options
41
+
42
+ addOptions() {
43
+ return {
44
+ /**
45
+ * Default filename for Markdown export (without extension)
46
+ */
47
+ defaultFilename: "document",
48
+
49
+ /**
50
+ * Default options for Markdown export
51
+ */
52
+ markdownOptions: {},
53
+
54
+ /**
55
+ * Default options for HTML export
56
+ */
57
+ htmlOptions: {
58
+ includeStyles: true,
59
+ inlineStyles: true,
60
+ includeWrapper: true
61
+ },
62
+
63
+ /**
64
+ * Default options for PDF export
65
+ */
66
+ pdfOptions: {
67
+ pageSize: "a4",
68
+ orientation: "portrait",
69
+ margins: { top: 20, right: 20, bottom: 20, left: 20 }
70
+ },
71
+
72
+ /**
73
+ * Callback when export succeeds
74
+ * @param {string} format - Export format (markdown, html, pdf)
75
+ * @param {string} action - Action performed (download, copy)
76
+ */
77
+ onExportSuccess: null,
78
+
79
+ /**
80
+ * Callback when export fails
81
+ * @param {string} format - Export format
82
+ * @param {Error} error - Error that occurred
83
+ */
84
+ onExportError: null
85
+ }
86
+ },
87
+
88
+ // Commands
89
+
90
+ addCommands() {
91
+ return {
92
+ /**
93
+ * Export and download as Markdown file
94
+ * @param {Object} options - Export options
95
+ * @param {string} options.filename - Filename for download
96
+ * @param {boolean} options.includeFrontmatter - Include YAML frontmatter
97
+ * @param {Object} options.frontmatter - Frontmatter data
98
+ */
99
+ downloadMarkdown: (options = {}) => ({ editor }) => {
100
+ try {
101
+ const filename = options.filename || `${this.options.defaultFilename}.md`
102
+ const exportOptions = { ...this.options.markdownOptions, ...options }
103
+ const markdown = exportToMarkdown(editor.getJSON(), exportOptions)
104
+ downloadMarkdown(markdown, filename)
105
+ this._notifySuccess("markdown", "download")
106
+ return true
107
+ } catch (error) {
108
+ this._notifyError("markdown", error)
109
+ return false
110
+ }
111
+ },
112
+
113
+ /**
114
+ * Copy editor content as Markdown to clipboard
115
+ * @param {Object} options - Export options
116
+ */
117
+ copyMarkdown: (options = {}) => ({ editor }) => {
118
+ try {
119
+ const exportOptions = { ...this.options.markdownOptions, ...options }
120
+ const markdown = exportToMarkdown(editor.getJSON(), exportOptions)
121
+ copyMarkdownToClipboard(markdown).then(success => {
122
+ if (success) {
123
+ this._notifySuccess("markdown", "copy")
124
+ }
125
+ })
126
+ return true
127
+ } catch (error) {
128
+ this._notifyError("markdown", error)
129
+ return false
130
+ }
131
+ },
132
+
133
+ /**
134
+ * Export and download as HTML file
135
+ * @param {Object} options - Export options
136
+ * @param {string} options.filename - Filename for download
137
+ * @param {boolean} options.includeStyles - Include CSS styles
138
+ * @param {boolean} options.inlineStyles - Embed styles in document
139
+ * @param {string} options.classPrefix - CSS class prefix
140
+ * @param {string} options.theme - Theme (light, dark, auto)
141
+ */
142
+ downloadHTML: (options = {}) => ({ editor }) => {
143
+ try {
144
+ const filename = options.filename || `${this.options.defaultFilename}.html`
145
+ const exportOptions = { ...this.options.htmlOptions, ...options }
146
+ const html = exportToHTML(editor, exportOptions)
147
+ downloadHTML(html, filename)
148
+ this._notifySuccess("html", "download")
149
+ return true
150
+ } catch (error) {
151
+ this._notifyError("html", error)
152
+ return false
153
+ }
154
+ },
155
+
156
+ /**
157
+ * Copy editor content as HTML to clipboard
158
+ * @param {Object} options - Export options
159
+ */
160
+ copyHTML: (options = {}) => ({ editor }) => {
161
+ try {
162
+ const exportOptions = {
163
+ ...this.options.htmlOptions,
164
+ ...options,
165
+ includeWrapper: false,
166
+ includeStyles: false
167
+ }
168
+ const html = exportToHTML(editor, exportOptions)
169
+ copyHTMLToClipboard(html).then(success => {
170
+ if (success) {
171
+ this._notifySuccess("html", "copy")
172
+ }
173
+ })
174
+ return true
175
+ } catch (error) {
176
+ this._notifyError("html", error)
177
+ return false
178
+ }
179
+ },
180
+
181
+ /**
182
+ * Export and download as PDF file
183
+ * @param {Object} options - Export options
184
+ * @param {string} options.filename - Filename for download
185
+ * @param {string} options.pageSize - Page size (a4, letter, legal)
186
+ * @param {string} options.orientation - Orientation (portrait, landscape)
187
+ * @param {Object} options.margins - Margins in mm
188
+ */
189
+ downloadPDF: (options = {}) => ({ editor }) => {
190
+ try {
191
+ const filename = options.filename || `${this.options.defaultFilename}.pdf`
192
+ const exportOptions = { ...this.options.pdfOptions, ...options, filename }
193
+ exportToPDF(editor, exportOptions).then(() => {
194
+ this._notifySuccess("pdf", "download")
195
+ }).catch(error => {
196
+ this._notifyError("pdf", error)
197
+ })
198
+ return true
199
+ } catch (error) {
200
+ this._notifyError("pdf", error)
201
+ return false
202
+ }
203
+ },
204
+
205
+ /**
206
+ * Get Markdown string without downloading
207
+ * @param {Object} options - Export options
208
+ * @returns {string} Markdown content
209
+ */
210
+ getMarkdown: (options = {}) => ({ editor }) => {
211
+ const exportOptions = { ...this.options.markdownOptions, ...options }
212
+ return exportToMarkdown(editor.getJSON(), exportOptions)
213
+ },
214
+
215
+ /**
216
+ * Get HTML string without downloading
217
+ * @param {Object} options - Export options
218
+ * @returns {string} HTML content
219
+ */
220
+ getHTML: (options = {}) => ({ editor }) => {
221
+ const exportOptions = { ...this.options.htmlOptions, ...options }
222
+ return exportToHTML(editor, exportOptions)
223
+ }
224
+ }
225
+ },
226
+
227
+ // Keyboard Shortcuts
228
+
229
+ addKeyboardShortcuts() {
230
+ return {
231
+ // Download shortcuts (Mod-Alt)
232
+ "Mod-Alt-m": () => this.editor.commands.downloadMarkdown(),
233
+ "Mod-Alt-h": () => this.editor.commands.downloadHTML(),
234
+ "Mod-Alt-p": () => this.editor.commands.downloadPDF(),
235
+
236
+ // Copy shortcuts (Mod-Alt-Shift)
237
+ "Mod-Alt-Shift-m": () => this.editor.commands.copyMarkdown(),
238
+ "Mod-Alt-Shift-h": () => this.editor.commands.copyHTML()
239
+ }
240
+ },
241
+
242
+ // Helpers (underscore prefix for internal methods in TipTap extensions)
243
+
244
+ _notifySuccess(format, action) {
245
+ if (this.options.onExportSuccess) {
246
+ this.options.onExportSuccess(format, action)
247
+ }
248
+
249
+ // Dispatch DOM event for external listeners
250
+ const event = new CustomEvent("inkpen:export-success", {
251
+ bubbles: true,
252
+ detail: { format, action }
253
+ })
254
+ this.editor.view.dom.dispatchEvent(event)
255
+ },
256
+
257
+ _notifyError(format, error) {
258
+ console.error(`Export to ${format} failed:`, error)
259
+
260
+ if (this.options.onExportError) {
261
+ this.options.onExportError(format, error)
262
+ }
263
+
264
+ // Dispatch DOM event for external listeners
265
+ const event = new CustomEvent("inkpen:export-error", {
266
+ bubbles: true,
267
+ detail: { format, error }
268
+ })
269
+ this.editor.view.dom.dispatchEvent(event)
270
+ }
271
+ })