@autumnsgrove/groveengine 0.6.2 → 0.6.4

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 (79) hide show
  1. package/LICENSE +378 -0
  2. package/dist/auth/jwt.d.ts +10 -4
  3. package/dist/auth/jwt.js +18 -4
  4. package/dist/auth/session.d.ts +22 -15
  5. package/dist/auth/session.js +35 -16
  6. package/dist/components/admin/GutterManager.svelte +81 -139
  7. package/dist/components/admin/GutterManager.svelte.d.ts +6 -6
  8. package/dist/components/admin/MarkdownEditor.svelte +80 -23
  9. package/dist/components/admin/MarkdownEditor.svelte.d.ts +14 -8
  10. package/dist/components/admin/composables/useAmbientSounds.svelte.d.ts +52 -2
  11. package/dist/components/admin/composables/useAmbientSounds.svelte.js +38 -4
  12. package/dist/components/admin/composables/useCommandPalette.svelte.d.ts +80 -10
  13. package/dist/components/admin/composables/useCommandPalette.svelte.js +45 -5
  14. package/dist/components/admin/composables/useDraftManager.svelte.d.ts +76 -14
  15. package/dist/components/admin/composables/useDraftManager.svelte.js +44 -10
  16. package/dist/components/admin/composables/useEditorTheme.svelte.d.ts +168 -2
  17. package/dist/components/admin/composables/useEditorTheme.svelte.js +40 -7
  18. package/dist/components/admin/composables/useSlashCommands.svelte.d.ts +94 -22
  19. package/dist/components/admin/composables/useSlashCommands.svelte.js +58 -9
  20. package/dist/components/admin/composables/useSnippets.svelte.d.ts +51 -2
  21. package/dist/components/admin/composables/useSnippets.svelte.js +35 -3
  22. package/dist/components/admin/composables/useWritingSession.svelte.d.ts +64 -6
  23. package/dist/components/admin/composables/useWritingSession.svelte.js +42 -5
  24. package/dist/components/custom/ContentWithGutter.svelte +53 -23
  25. package/dist/components/custom/ContentWithGutter.svelte.d.ts +6 -14
  26. package/dist/components/custom/GutterItem.svelte +1 -1
  27. package/dist/components/custom/LeftGutter.svelte +43 -13
  28. package/dist/components/custom/LeftGutter.svelte.d.ts +6 -6
  29. package/dist/config/ai-models.js +1 -1
  30. package/dist/groveauth/client.js +11 -11
  31. package/dist/index.d.ts +3 -1
  32. package/dist/index.js +2 -2
  33. package/dist/server/logger.d.ts +74 -26
  34. package/dist/server/logger.js +133 -184
  35. package/dist/server/services/cache.js +1 -10
  36. package/dist/ui/components/charts/ActivityOverview.svelte +14 -3
  37. package/dist/ui/components/charts/ActivityOverview.svelte.d.ts +10 -7
  38. package/dist/ui/components/charts/RepoBreakdown.svelte +9 -3
  39. package/dist/ui/components/charts/RepoBreakdown.svelte.d.ts +12 -11
  40. package/dist/ui/components/charts/Sparkline.svelte +18 -7
  41. package/dist/ui/components/charts/Sparkline.svelte.d.ts +21 -2
  42. package/dist/ui/components/gallery/ImageGallery.svelte +12 -8
  43. package/dist/ui/components/gallery/ImageGallery.svelte.d.ts +2 -2
  44. package/dist/ui/components/gallery/Lightbox.svelte +5 -2
  45. package/dist/ui/components/gallery/ZoomableImage.svelte +8 -5
  46. package/dist/ui/components/primitives/accordion/index.d.ts +1 -1
  47. package/dist/ui/components/primitives/input/input.svelte.d.ts +1 -1
  48. package/dist/ui/components/primitives/tabs/index.d.ts +1 -1
  49. package/dist/ui/components/primitives/textarea/textarea.svelte.d.ts +1 -1
  50. package/dist/ui/components/ui/Button.svelte +5 -0
  51. package/dist/ui/components/ui/Button.svelte.d.ts +4 -1
  52. package/dist/ui/components/ui/Input.svelte +4 -0
  53. package/dist/ui/components/ui/Input.svelte.d.ts +3 -1
  54. package/dist/ui/components/ui/Logo.svelte +86 -0
  55. package/dist/ui/components/ui/Logo.svelte.d.ts +25 -0
  56. package/dist/ui/components/ui/LogoLoader.svelte +71 -0
  57. package/dist/ui/components/ui/LogoLoader.svelte.d.ts +9 -0
  58. package/dist/ui/components/ui/index.d.ts +2 -0
  59. package/dist/ui/components/ui/index.js +2 -0
  60. package/dist/ui/tailwind.preset.js +8 -8
  61. package/dist/utils/api.js +2 -1
  62. package/dist/utils/debounce.d.ts +4 -3
  63. package/dist/utils/debounce.js +10 -6
  64. package/dist/utils/gallery.d.ts +58 -32
  65. package/dist/utils/gallery.js +111 -129
  66. package/dist/utils/gutter.d.ts +47 -26
  67. package/dist/utils/gutter.js +116 -124
  68. package/dist/utils/imageProcessor.d.ts +66 -19
  69. package/dist/utils/imageProcessor.js +31 -10
  70. package/dist/utils/index.d.ts +11 -11
  71. package/dist/utils/index.js +4 -3
  72. package/dist/utils/json.js +1 -1
  73. package/dist/utils/markdown.d.ts +183 -103
  74. package/dist/utils/markdown.js +517 -678
  75. package/dist/utils/sanitize.d.ts +22 -12
  76. package/dist/utils/sanitize.js +268 -282
  77. package/dist/utils/validation.js +4 -3
  78. package/package.json +23 -23
  79. package/static/fonts/alagard.ttf +0 -0
@@ -5,17 +5,43 @@
5
5
  import Select from "../../ui/components/ui/Select.svelte";
6
6
  import { toast } from "../../ui/components/ui/toast";
7
7
 
8
+ /**
9
+ * @typedef {Object} GutterItem
10
+ * @property {string} type
11
+ * @property {string} [anchor]
12
+ * @property {string} [content]
13
+ * @property {string} [url]
14
+ * @property {string} [file]
15
+ * @property {string} [caption]
16
+ * @property {GalleryImage[]} [images]
17
+ */
18
+
19
+ /**
20
+ * @typedef {Object} GalleryImage
21
+ * @property {string} url
22
+ * @property {string} [alt]
23
+ * @property {string} [caption]
24
+ */
25
+
26
+ /**
27
+ * @typedef {Object} CdnImage
28
+ * @property {string} key
29
+ * @property {string} url
30
+ */
31
+
8
32
  // Props
9
33
  let {
10
- gutterItems = $bindable([]),
11
- onInsertAnchor = (anchorName) => {},
12
- availableAnchors = [],
34
+ gutterItems = $bindable(/** @type {GutterItem[]} */ ([])),
35
+ onInsertAnchor = /** @type {(anchorName: string) => void} */ ((anchorName) => {}),
36
+ availableAnchors = /** @type {string[]} */ ([]),
13
37
  } = $props();
14
38
 
15
39
  // State
16
40
  let showAddModal = $state(false);
41
+ /** @type {number | null} */
17
42
  let editingIndex = $state(null);
18
43
  let showImagePicker = $state(false);
44
+ /** @type {((url: string) => void) | null} */
19
45
  let imagePickerCallback = $state(null);
20
46
 
21
47
  // Form state for add/edit
@@ -24,9 +50,11 @@
24
50
  let itemContent = $state("");
25
51
  let itemCaption = $state("");
26
52
  let itemUrl = $state("");
53
+ /** @type {GalleryImage[]} */
27
54
  let galleryImages = $state([]);
28
55
 
29
56
  // Image picker state
57
+ /** @type {CdnImage[]} */
30
58
  let cdnImages = $state([]);
31
59
  let cdnLoading = $state(false);
32
60
  let cdnFilter = $state("");
@@ -46,6 +74,7 @@
46
74
  showAddModal = true;
47
75
  }
48
76
 
77
+ /** @param {number} index */
49
78
  function openEditModal(index) {
50
79
  const item = gutterItems[index];
51
80
  itemType = item.type;
@@ -65,6 +94,7 @@
65
94
  }
66
95
 
67
96
  function saveItem() {
97
+ /** @type {GutterItem} */
68
98
  const newItem = {
69
99
  type: itemType,
70
100
  anchor: itemAnchor,
@@ -89,11 +119,16 @@
89
119
  closeModal();
90
120
  }
91
121
 
122
+ /** @param {number} index */
92
123
  function deleteItem(index) {
93
- gutterItems = gutterItems.filter((_, i) => i !== index);
124
+ gutterItems = gutterItems.filter((/** @type {GutterItem} */ _, /** @type {number} */ i) => i !== index);
94
125
  toast.success("Gutter item deleted");
95
126
  }
96
127
 
128
+ /**
129
+ * @param {number} index
130
+ * @param {number} direction
131
+ */
97
132
  function moveItem(index, direction) {
98
133
  const newIndex = index + direction;
99
134
  if (newIndex < 0 || newIndex >= gutterItems.length) return;
@@ -106,6 +141,7 @@
106
141
  }
107
142
 
108
143
  // Generate anchor name from text
144
+ /** @param {string} text */
109
145
  function generateAnchorName(text) {
110
146
  return text
111
147
  .toLowerCase()
@@ -138,7 +174,7 @@
138
174
 
139
175
  if (response.ok) {
140
176
  const imageExtensions = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"];
141
- cdnImages = data.images.filter((img) => {
177
+ cdnImages = data.images.filter((/** @type {CdnImage} */ img) => {
142
178
  const key = img.key.toLowerCase();
143
179
  return imageExtensions.some((ext) => key.endsWith(ext));
144
180
  });
@@ -152,12 +188,14 @@
152
188
  }
153
189
  }
154
190
 
191
+ /** @param {(url: string) => void} callback */
155
192
  function openImagePicker(callback) {
156
193
  imagePickerCallback = callback;
157
194
  showImagePicker = true;
158
195
  loadCdnImages();
159
196
  }
160
197
 
198
+ /** @param {CdnImage} image */
161
199
  function selectImage(image) {
162
200
  if (imagePickerCallback) {
163
201
  imagePickerCallback(image.url);
@@ -181,16 +219,23 @@
181
219
  });
182
220
  }
183
221
 
222
+ /** @param {number} index */
184
223
  function removeGalleryImage(index) {
185
- galleryImages = galleryImages.filter((_, i) => i !== index);
224
+ galleryImages = galleryImages.filter((/** @type {GalleryImage} */ _, /** @type {number} */ i) => i !== index);
186
225
  }
187
226
 
227
+ /**
228
+ * @param {number} index
229
+ * @param {keyof GalleryImage} field
230
+ * @param {string} value
231
+ */
188
232
  function updateGalleryImage(index, field, value) {
189
233
  galleryImages[index][field] = value;
190
234
  galleryImages = [...galleryImages];
191
235
  }
192
236
 
193
237
  // Get preview of item content
238
+ /** @param {GutterItem} item */
194
239
  function getItemPreview(item) {
195
240
  if (item.type === "comment" && item.content) {
196
241
  return item.content.substring(0, 50) + (item.content.length > 50 ? "..." : "");
@@ -204,6 +249,7 @@
204
249
  return "";
205
250
  }
206
251
 
252
+ /** @param {string} type */
207
253
  function getTypeIcon(type) {
208
254
  switch (type) {
209
255
  case "comment":
@@ -269,17 +315,19 @@
269
315
  </div>
270
316
 
271
317
  <!-- Add/Edit Modal -->
272
- <Dialog bind:open={showAddModal}>
273
- <h3 slot="title">{editingIndex !== null ? "Edit" : "Add"} Gutter Item</h3>
274
-
275
- <div class="form-group">
276
- <label for="item-type">Type</label>
277
- <Select id="item-type" bind:value={itemType}>
278
- <option value="comment">Comment (Markdown)</option>
279
- <option value="photo">Photo</option>
280
- <option value="gallery">Image Gallery</option>
281
- </Select>
282
- </div>
318
+ <Dialog bind:open={showAddModal} title={editingIndex !== null ? "Edit Gutter Item" : "Add Gutter Item"}>
319
+ {#snippet children()}
320
+ <div class="form-group">
321
+ <label for="item-type">Type</label>
322
+ <Select
323
+ bind:value={itemType}
324
+ options={[
325
+ { value: "comment", label: "Comment (Markdown)" },
326
+ { value: "photo", label: "Photo" },
327
+ { value: "gallery", label: "Image Gallery" }
328
+ ]}
329
+ />
330
+ </div>
283
331
 
284
332
  <div class="form-group">
285
333
  <label for="item-anchor">Anchor</label>
@@ -369,7 +417,7 @@
369
417
 
370
418
  {#if itemType === "gallery"}
371
419
  <div class="form-group">
372
- <label>Gallery Images</label>
420
+ <div class="gallery-label">Gallery Images</div>
373
421
  <div class="gallery-list">
374
422
  {#each galleryImages as image, i (i)}
375
423
  <div class="gallery-image-item">
@@ -378,14 +426,14 @@
378
426
  <Input
379
427
  type="text"
380
428
  value={image.alt}
381
- oninput={(e) => updateGalleryImage(i, "alt", e.target.value)}
429
+ oninput={(/** @type {Event} */ e) => updateGalleryImage(i, "alt", /** @type {HTMLInputElement} */ (e.target).value)}
382
430
  placeholder="Alt text"
383
431
  class="small"
384
432
  />
385
433
  <Input
386
434
  type="text"
387
435
  value={image.caption}
388
- oninput={(e) => updateGalleryImage(i, "caption", e.target.value)}
436
+ oninput={(/** @type {Event} */ e) => updateGalleryImage(i, "caption", /** @type {HTMLInputElement} */ (e.target).value)}
389
437
  placeholder="Caption"
390
438
  class="small"
391
439
  />
@@ -403,20 +451,20 @@
403
451
  </button>
404
452
  </div>
405
453
  {/if}
454
+ {/snippet}
406
455
 
407
- <div slot="footer" style="display: flex; gap: 0.75rem; justify-content: flex-end;">
456
+ {#snippet footer()}
408
457
  <Button variant="outline" onclick={closeModal}>Cancel</Button>
409
458
  <Button onclick={saveItem}>
410
459
  {editingIndex !== null ? "Update" : "Add"} Item
411
460
  </Button>
412
- </div>
461
+ {/snippet}
413
462
  </Dialog>
414
463
 
415
464
  <!-- Image Picker Modal -->
416
- <Dialog bind:open={showImagePicker}>
417
- <h3 slot="title">Select Image from CDN</h3>
418
-
419
- <div class="picker-controls">
465
+ <Dialog bind:open={showImagePicker} title="Select Image from CDN">
466
+ {#snippet children()}
467
+ <div class="picker-controls">
420
468
  <Input
421
469
  type="text"
422
470
  bind:value={cdnFilter}
@@ -444,10 +492,11 @@
444
492
  {/each}
445
493
  {/if}
446
494
  </div>
495
+ {/snippet}
447
496
 
448
- <div slot="footer" style="display: flex; gap: 0.75rem; justify-content: flex-end;">
497
+ {#snippet footer()}
449
498
  <Button variant="outline" onclick={closeImagePicker}>Cancel</Button>
450
- </div>
499
+ {/snippet}
451
500
  </Dialog>
452
501
 
453
502
  <style>
@@ -577,43 +626,13 @@
577
626
  text-overflow: ellipsis;
578
627
  }
579
628
 
580
- /* Modal Styles */
581
- .modal-overlay {
582
- position: fixed;
583
- top: 0;
584
- left: 0;
585
- right: 0;
586
- bottom: 0;
587
- background: rgba(0, 0, 0, 0.7);
588
- display: flex;
589
- align-items: center;
590
- justify-content: center;
591
- z-index: 1000;
592
- padding: 1rem;
593
- }
594
-
595
- .modal-content {
596
- background: #1e1e1e;
597
- border: 1px solid #3a3a3a;
598
- border-radius: 8px;
599
- padding: 1.5rem;
600
- max-width: 500px;
601
- width: 100%;
602
- max-height: 80vh;
603
- overflow-y: auto;
604
- }
605
-
606
- .modal-content h3 {
607
- margin: 0 0 1.25rem 0;
608
- color: #d4d4d4;
609
- font-size: 1.1rem;
610
- }
611
-
629
+ /* Form Styles */
612
630
  .form-group {
613
631
  margin-bottom: 1rem;
614
632
  }
615
633
 
616
- .form-group label {
634
+ .form-group label,
635
+ .gallery-label {
617
636
  display: block;
618
637
  margin-bottom: 0.4rem;
619
638
  font-size: 0.85rem;
@@ -636,11 +655,6 @@
636
655
  border-color: #4a7c4a;
637
656
  }
638
657
 
639
- .form-input.small {
640
- padding: 0.35rem 0.5rem;
641
- font-size: 0.8rem;
642
- }
643
-
644
658
  .form-textarea {
645
659
  resize: vertical;
646
660
  min-height: 100px;
@@ -672,23 +686,6 @@
672
686
  flex: 1;
673
687
  }
674
688
 
675
- .insert-anchor-btn,
676
- .browse-btn {
677
- padding: 0.5rem 0.75rem;
678
- background: #2d4a2d;
679
- color: #a8dca8;
680
- border: 1px solid #3d5a3d;
681
- border-radius: 4px;
682
- font-size: 0.8rem;
683
- white-space: nowrap;
684
- cursor: pointer;
685
- }
686
-
687
- .insert-anchor-btn:hover,
688
- .browse-btn:hover {
689
- background: #3d5a3d;
690
- }
691
-
692
689
  .available-anchors {
693
690
  display: flex;
694
691
  flex-wrap: wrap;
@@ -790,49 +787,7 @@
790
787
  color: #8bc48b;
791
788
  }
792
789
 
793
- .modal-actions {
794
- display: flex;
795
- justify-content: flex-end;
796
- gap: 0.75rem;
797
- margin-top: 1.5rem;
798
- padding-top: 1rem;
799
- border-top: 1px solid #3a3a3a;
800
- }
801
-
802
- .cancel-btn,
803
- .save-btn {
804
- padding: 0.5rem 1rem;
805
- border-radius: 4px;
806
- font-size: 0.9rem;
807
- cursor: pointer;
808
- transition: all 0.15s ease;
809
- }
810
-
811
- .cancel-btn {
812
- background: transparent;
813
- border: 1px solid #3a3a3a;
814
- color: #9d9d9d;
815
- }
816
-
817
- .cancel-btn:hover {
818
- background: #3a3a3a;
819
- }
820
-
821
- .save-btn {
822
- background: #4a7c4a;
823
- border: none;
824
- color: #c8f0c8;
825
- }
826
-
827
- .save-btn:hover {
828
- background: #5a9c5a;
829
- }
830
-
831
- /* Image Picker Modal */
832
- .image-picker-modal {
833
- max-width: 700px;
834
- }
835
-
790
+ /* Image Picker */
836
791
  .picker-controls {
837
792
  display: flex;
838
793
  gap: 0.5rem;
@@ -843,19 +798,6 @@
843
798
  flex: 1;
844
799
  }
845
800
 
846
- .filter-btn {
847
- padding: 0.5rem 1rem;
848
- background: #3a3a3a;
849
- border: none;
850
- border-radius: 4px;
851
- color: #d4d4d4;
852
- cursor: pointer;
853
- }
854
-
855
- .filter-btn:hover {
856
- background: #4a4a4a;
857
- }
858
-
859
801
  .image-grid {
860
802
  display: grid;
861
803
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
@@ -4,12 +4,12 @@ type GutterManager = {
4
4
  $set?(props: Partial<$$ComponentProps>): void;
5
5
  };
6
6
  declare const GutterManager: import("svelte").Component<{
7
- gutterItems?: any[];
8
- onInsertAnchor?: Function;
9
- availableAnchors?: any[];
7
+ gutterItems?: any;
8
+ onInsertAnchor?: any;
9
+ availableAnchors?: any;
10
10
  }, {}, "gutterItems">;
11
11
  type $$ComponentProps = {
12
- gutterItems?: any[];
13
- onInsertAnchor?: Function;
14
- availableAnchors?: any[];
12
+ gutterItems?: any;
13
+ onInsertAnchor?: any;
14
+ availableAnchors?: any;
15
15
  };