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,453 @@
1
+ /**
2
+ * Enhanced Image Extension Styles
3
+ *
4
+ * Styles for resizable, alignable images with captions and lightbox.
5
+ *
6
+ * @since 0.5.0
7
+ */
8
+
9
+ /* ==========================================================================
10
+ Image Container
11
+ ========================================================================== */
12
+
13
+ .inkpen-image {
14
+ position: relative;
15
+ display: flex;
16
+ flex-direction: column;
17
+ margin: 1.5rem 0;
18
+ max-width: 100%;
19
+ }
20
+
21
+ /* Alignment variants */
22
+ .inkpen-image--left {
23
+ align-items: flex-start;
24
+ }
25
+
26
+ .inkpen-image--center {
27
+ align-items: center;
28
+ }
29
+
30
+ .inkpen-image--right {
31
+ align-items: flex-end;
32
+ }
33
+
34
+ .inkpen-image--full {
35
+ align-items: stretch;
36
+ }
37
+
38
+ .inkpen-image--full .inkpen-image__wrapper {
39
+ width: 100%;
40
+ }
41
+
42
+ .inkpen-image--full img {
43
+ width: 100%;
44
+ }
45
+
46
+ /* ==========================================================================
47
+ Image Wrapper (contains image + resize handles)
48
+ ========================================================================== */
49
+
50
+ .inkpen-image__wrapper {
51
+ position: relative;
52
+ display: inline-block;
53
+ max-width: 100%;
54
+ line-height: 0;
55
+ }
56
+
57
+ .inkpen-image__wrapper img {
58
+ display: block;
59
+ max-width: 100%;
60
+ height: auto;
61
+ border-radius: var(--inkpen-radius);
62
+ cursor: default;
63
+ }
64
+
65
+ /* Link wrapper */
66
+ .inkpen-image__wrapper a {
67
+ display: block;
68
+ line-height: 0;
69
+ }
70
+
71
+ .inkpen-image__wrapper a img {
72
+ cursor: pointer;
73
+ }
74
+
75
+ /* ==========================================================================
76
+ Resize Handles
77
+ ========================================================================== */
78
+
79
+ .inkpen-image__resize-handle {
80
+ position: absolute;
81
+ width: 12px;
82
+ height: 12px;
83
+ background: var(--inkpen-color-primary, #3b82f6);
84
+ border: 2px solid white;
85
+ border-radius: 50%;
86
+ opacity: 0;
87
+ transition: opacity var(--inkpen-animation-fast, 100ms) ease-out;
88
+ z-index: 10;
89
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
90
+ }
91
+
92
+ .inkpen-image:hover .inkpen-image__resize-handle,
93
+ .inkpen-image.is-selected .inkpen-image__resize-handle {
94
+ opacity: 1;
95
+ }
96
+
97
+ .inkpen-image__resize-handle--nw {
98
+ top: -6px;
99
+ left: -6px;
100
+ cursor: nw-resize;
101
+ }
102
+
103
+ .inkpen-image__resize-handle--ne {
104
+ top: -6px;
105
+ right: -6px;
106
+ cursor: ne-resize;
107
+ }
108
+
109
+ .inkpen-image__resize-handle--sw {
110
+ bottom: -6px;
111
+ left: -6px;
112
+ cursor: sw-resize;
113
+ }
114
+
115
+ .inkpen-image__resize-handle--se {
116
+ bottom: -6px;
117
+ right: -6px;
118
+ cursor: se-resize;
119
+ }
120
+
121
+ /* ==========================================================================
122
+ Caption
123
+ ========================================================================== */
124
+
125
+ .inkpen-image__caption {
126
+ margin-top: 0.5rem;
127
+ padding: 0.25rem 0.5rem;
128
+ font-size: 0.875rem;
129
+ color: var(--inkpen-color-text-muted, #6b7280);
130
+ text-align: center;
131
+ line-height: 1.4;
132
+ outline: none;
133
+ border-radius: var(--inkpen-radius, 0.375rem);
134
+ min-height: 1.4em;
135
+ transition: background var(--inkpen-animation-fast, 100ms) ease-out;
136
+ }
137
+
138
+ .inkpen-image__caption:empty::before {
139
+ content: attr(placeholder);
140
+ color: var(--inkpen-color-text-muted, #6b7280);
141
+ opacity: 0.5;
142
+ }
143
+
144
+ .inkpen-image__caption:focus {
145
+ background: var(--inkpen-color-selection, rgba(59, 130, 246, 0.1));
146
+ }
147
+
148
+ /* ==========================================================================
149
+ Alignment Controls
150
+ ========================================================================== */
151
+
152
+ .inkpen-image__controls {
153
+ position: absolute;
154
+ top: 8px;
155
+ left: 50%;
156
+ transform: translateX(-50%);
157
+ display: flex;
158
+ align-items: center;
159
+ gap: 2px;
160
+ padding: 4px;
161
+ background: var(--inkpen-toolbar-bg, #ffffff);
162
+ border: 1px solid var(--inkpen-color-border, #e5e7eb);
163
+ border-radius: var(--inkpen-radius, 0.375rem);
164
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
165
+ opacity: 0;
166
+ visibility: hidden;
167
+ transition: opacity var(--inkpen-animation-fast, 100ms) ease-out,
168
+ visibility var(--inkpen-animation-fast, 100ms) ease-out;
169
+ z-index: 20;
170
+ }
171
+
172
+ .inkpen-image:hover .inkpen-image__controls,
173
+ .inkpen-image.is-selected .inkpen-image__controls {
174
+ opacity: 1;
175
+ visibility: visible;
176
+ }
177
+
178
+ .inkpen-image__control {
179
+ display: flex;
180
+ align-items: center;
181
+ justify-content: center;
182
+ width: 28px;
183
+ height: 28px;
184
+ padding: 0;
185
+ background: transparent;
186
+ border: none;
187
+ border-radius: 4px;
188
+ color: var(--inkpen-color-text, #1a1a1a);
189
+ cursor: pointer;
190
+ transition: background var(--inkpen-animation-fast, 100ms) ease-out,
191
+ color var(--inkpen-animation-fast, 100ms) ease-out;
192
+ }
193
+
194
+ .inkpen-image__control:hover {
195
+ background: var(--inkpen-color-selection, rgba(59, 130, 246, 0.1));
196
+ }
197
+
198
+ .inkpen-image__control.is-active {
199
+ background: var(--inkpen-color-primary, #3b82f6);
200
+ color: white;
201
+ }
202
+
203
+ .inkpen-image__control svg {
204
+ width: 16px;
205
+ height: 16px;
206
+ }
207
+
208
+ .inkpen-image__divider {
209
+ width: 1px;
210
+ height: 20px;
211
+ background: var(--inkpen-color-border, #e5e7eb);
212
+ margin: 0 4px;
213
+ }
214
+
215
+ /* ==========================================================================
216
+ Selection State
217
+ ========================================================================== */
218
+
219
+ .inkpen-image.is-selected .inkpen-image__wrapper::after {
220
+ content: "";
221
+ position: absolute;
222
+ inset: -2px;
223
+ border: 2px solid var(--inkpen-color-primary, #3b82f6);
224
+ border-radius: calc(var(--inkpen-radius, 0.375rem) + 2px);
225
+ pointer-events: none;
226
+ }
227
+
228
+ /* ProseMirror selection */
229
+ .inkpen-image.ProseMirror-selectednode .inkpen-image__wrapper::after {
230
+ content: "";
231
+ position: absolute;
232
+ inset: -2px;
233
+ border: 2px solid var(--inkpen-color-primary, #3b82f6);
234
+ border-radius: calc(var(--inkpen-radius, 0.375rem) + 2px);
235
+ pointer-events: none;
236
+ }
237
+
238
+ /* ==========================================================================
239
+ Lightbox
240
+ ========================================================================== */
241
+
242
+ .inkpen-lightbox {
243
+ position: fixed;
244
+ inset: 0;
245
+ z-index: 99999;
246
+ display: flex;
247
+ align-items: center;
248
+ justify-content: center;
249
+ opacity: 0;
250
+ transition: opacity 200ms ease-out;
251
+ }
252
+
253
+ .inkpen-lightbox.is-open {
254
+ opacity: 1;
255
+ }
256
+
257
+ .inkpen-lightbox.is-closing {
258
+ opacity: 0;
259
+ }
260
+
261
+ .inkpen-lightbox__backdrop {
262
+ position: absolute;
263
+ inset: 0;
264
+ background: rgba(0, 0, 0, 0.9);
265
+ cursor: zoom-out;
266
+ }
267
+
268
+ .inkpen-lightbox__content {
269
+ position: relative;
270
+ max-width: 90vw;
271
+ max-height: 90vh;
272
+ z-index: 1;
273
+ }
274
+
275
+ .inkpen-lightbox__content img {
276
+ display: block;
277
+ max-width: 90vw;
278
+ max-height: 90vh;
279
+ object-fit: contain;
280
+ border-radius: var(--inkpen-radius, 0.375rem);
281
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
282
+ }
283
+
284
+ .inkpen-lightbox__close {
285
+ position: absolute;
286
+ top: -40px;
287
+ right: 0;
288
+ display: flex;
289
+ align-items: center;
290
+ justify-content: center;
291
+ width: 32px;
292
+ height: 32px;
293
+ padding: 0;
294
+ background: rgba(255, 255, 255, 0.1);
295
+ border: none;
296
+ border-radius: 50%;
297
+ color: white;
298
+ cursor: pointer;
299
+ transition: background 150ms ease-out;
300
+ }
301
+
302
+ .inkpen-lightbox__close:hover {
303
+ background: rgba(255, 255, 255, 0.2);
304
+ }
305
+
306
+ .inkpen-lightbox__close:focus {
307
+ outline: 2px solid white;
308
+ outline-offset: 2px;
309
+ }
310
+
311
+ /* ==========================================================================
312
+ Loading State
313
+ ========================================================================== */
314
+
315
+ .inkpen-image--loading .inkpen-image__wrapper::before {
316
+ content: "";
317
+ position: absolute;
318
+ inset: 0;
319
+ background: linear-gradient(
320
+ 90deg,
321
+ var(--inkpen-color-border, #e5e7eb) 25%,
322
+ var(--inkpen-color-selection, rgba(59, 130, 246, 0.1)) 50%,
323
+ var(--inkpen-color-border, #e5e7eb) 75%
324
+ );
325
+ background-size: 200% 100%;
326
+ animation: inkpen-image-shimmer 1.5s ease-in-out infinite;
327
+ border-radius: var(--inkpen-radius, 0.375rem);
328
+ }
329
+
330
+ @keyframes inkpen-image-shimmer {
331
+ 0% {
332
+ background-position: 200% 0;
333
+ }
334
+ 100% {
335
+ background-position: -200% 0;
336
+ }
337
+ }
338
+
339
+ /* ==========================================================================
340
+ Dark Mode
341
+ ========================================================================== */
342
+
343
+ [data-theme="dark"],
344
+ .dark {
345
+ .inkpen-lightbox__backdrop {
346
+ background: rgba(0, 0, 0, 0.95);
347
+ }
348
+
349
+ .inkpen-image__controls {
350
+ background: var(--inkpen-toolbar-bg, #1f2937);
351
+ border-color: var(--inkpen-color-border, #374151);
352
+ }
353
+
354
+ .inkpen-image__resize-handle {
355
+ border-color: #374151;
356
+ }
357
+ }
358
+
359
+ /* ==========================================================================
360
+ Mobile Optimizations
361
+ ========================================================================== */
362
+
363
+ @media (hover: none) and (pointer: coarse) {
364
+ /* Always show controls on mobile */
365
+ .inkpen-image__controls {
366
+ opacity: 1;
367
+ visibility: visible;
368
+ }
369
+
370
+ /* Larger touch targets */
371
+ .inkpen-image__control {
372
+ width: 36px;
373
+ height: 36px;
374
+ }
375
+
376
+ .inkpen-image__resize-handle {
377
+ width: 20px;
378
+ height: 20px;
379
+ opacity: 0.8;
380
+ }
381
+
382
+ .inkpen-image__resize-handle--nw {
383
+ top: -10px;
384
+ left: -10px;
385
+ }
386
+
387
+ .inkpen-image__resize-handle--ne {
388
+ top: -10px;
389
+ right: -10px;
390
+ }
391
+
392
+ .inkpen-image__resize-handle--sw {
393
+ bottom: -10px;
394
+ left: -10px;
395
+ }
396
+
397
+ .inkpen-image__resize-handle--se {
398
+ bottom: -10px;
399
+ right: -10px;
400
+ }
401
+
402
+ /* Lightbox close button */
403
+ .inkpen-lightbox__close {
404
+ width: 44px;
405
+ height: 44px;
406
+ top: -52px;
407
+ }
408
+ }
409
+
410
+ /* Small screens */
411
+ @media (max-width: 640px) {
412
+ .inkpen-image__controls {
413
+ padding: 2px;
414
+ gap: 1px;
415
+ }
416
+
417
+ .inkpen-image__divider {
418
+ margin: 0 2px;
419
+ }
420
+ }
421
+
422
+ /* ==========================================================================
423
+ Reduced Motion
424
+ ========================================================================== */
425
+
426
+ @media (prefers-reduced-motion: reduce) {
427
+ .inkpen-lightbox,
428
+ .inkpen-image__controls,
429
+ .inkpen-image__resize-handle,
430
+ .inkpen-image--loading .inkpen-image__wrapper::before {
431
+ transition: none;
432
+ animation: none;
433
+ }
434
+ }
435
+
436
+ /* ==========================================================================
437
+ Print Styles
438
+ ========================================================================== */
439
+
440
+ @media print {
441
+ .inkpen-image__controls,
442
+ .inkpen-image__resize-handle {
443
+ display: none;
444
+ }
445
+
446
+ .inkpen-image__caption {
447
+ color: #666;
448
+ }
449
+
450
+ .inkpen-lightbox {
451
+ display: none;
452
+ }
453
+ }