@autumnsgrove/groveengine 0.6.4 → 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 (58) hide show
  1. package/dist/auth/index.d.ts +1 -2
  2. package/dist/auth/index.js +8 -4
  3. package/dist/auth/session.d.ts +14 -33
  4. package/dist/auth/session.js +5 -103
  5. package/dist/components/admin/FloatingToolbar.svelte +373 -0
  6. package/dist/components/admin/FloatingToolbar.svelte.d.ts +17 -0
  7. package/dist/components/admin/MarkdownEditor.svelte +26 -347
  8. package/dist/components/admin/MarkdownEditor.svelte.d.ts +1 -1
  9. package/dist/components/admin/composables/index.d.ts +0 -2
  10. package/dist/components/admin/composables/index.js +0 -2
  11. package/dist/components/custom/ContentWithGutter.svelte +22 -25
  12. package/dist/components/custom/MobileTOC.svelte +20 -13
  13. package/dist/components/quota/UpgradePrompt.svelte +1 -1
  14. package/dist/server/services/database.d.ts +138 -0
  15. package/dist/server/services/database.js +234 -0
  16. package/dist/server/services/index.d.ts +5 -1
  17. package/dist/server/services/index.js +24 -2
  18. package/dist/server/services/turnstile.d.ts +66 -0
  19. package/dist/server/services/turnstile.js +131 -0
  20. package/dist/server/services/users.d.ts +104 -0
  21. package/dist/server/services/users.js +158 -0
  22. package/dist/styles/README.md +50 -0
  23. package/dist/styles/vine-pattern.css +24 -0
  24. package/dist/types/turnstile.d.ts +42 -0
  25. package/dist/ui/components/forms/TurnstileWidget.svelte +111 -0
  26. package/dist/ui/components/forms/TurnstileWidget.svelte.d.ts +14 -0
  27. package/dist/ui/components/primitives/dialog/dialog-overlay.svelte +1 -1
  28. package/dist/ui/components/primitives/sheet/sheet-overlay.svelte +1 -1
  29. package/dist/ui/components/ui/Glass.svelte +158 -0
  30. package/dist/ui/components/ui/Glass.svelte.d.ts +52 -0
  31. package/dist/ui/components/ui/GlassButton.svelte +157 -0
  32. package/dist/ui/components/ui/GlassButton.svelte.d.ts +39 -0
  33. package/dist/ui/components/ui/GlassCard.svelte +160 -0
  34. package/dist/ui/components/ui/GlassCard.svelte.d.ts +39 -0
  35. package/dist/ui/components/ui/GlassConfirmDialog.svelte +208 -0
  36. package/dist/ui/components/ui/GlassConfirmDialog.svelte.d.ts +52 -0
  37. package/dist/ui/components/ui/GlassOverlay.svelte +93 -0
  38. package/dist/ui/components/ui/GlassOverlay.svelte.d.ts +33 -0
  39. package/dist/ui/components/ui/Logo.svelte +161 -23
  40. package/dist/ui/components/ui/Logo.svelte.d.ts +4 -10
  41. package/dist/ui/components/ui/index.d.ts +5 -0
  42. package/dist/ui/components/ui/index.js +6 -0
  43. package/dist/ui/styles/grove.css +136 -0
  44. package/dist/ui/tokens/fonts.d.ts +69 -0
  45. package/dist/ui/tokens/fonts.js +341 -0
  46. package/dist/ui/tokens/index.d.ts +6 -5
  47. package/dist/ui/tokens/index.js +7 -6
  48. package/dist/utils/gutter.d.ts +2 -8
  49. package/dist/utils/markdown.d.ts +1 -0
  50. package/dist/utils/markdown.js +32 -11
  51. package/package.json +1 -1
  52. package/static/robots.txt +520 -0
  53. package/dist/auth/jwt.d.ts +0 -20
  54. package/dist/auth/jwt.js +0 -123
  55. package/dist/components/admin/composables/useCommandPalette.svelte.d.ts +0 -87
  56. package/dist/components/admin/composables/useCommandPalette.svelte.js +0 -158
  57. package/dist/components/admin/composables/useSlashCommands.svelte.d.ts +0 -104
  58. package/dist/components/admin/composables/useSlashCommands.svelte.js +0 -215
@@ -5,8 +5,9 @@
5
5
  import "../../styles/content.css";
6
6
  import { Button, Input, Logo } from '../../ui';
7
7
  import Dialog from "../../ui/components/ui/Dialog.svelte";
8
+ import FloatingToolbar from "./FloatingToolbar.svelte";
8
9
 
9
- // Import composables
10
+ // Import composables (simplified - removed command palette and slash commands)
10
11
  import {
11
12
  useAmbientSounds,
12
13
  soundLibrary,
@@ -15,8 +16,6 @@
15
16
  useSnippets,
16
17
  useDraftManager,
17
18
  useWritingSession,
18
- useSlashCommands,
19
- useCommandPalette,
20
19
  } from "./composables/index.js";
21
20
 
22
21
  /**
@@ -46,7 +45,7 @@
46
45
  let previewRef = $state(null);
47
46
  /** @type {HTMLElement | null} */
48
47
  let lineNumbersRef = $state(null);
49
- let showPreview = $state(true);
48
+ let showPreview = $state(false); // Default to false for Medium-style focused writing
50
49
  let cursorLine = $state(1);
51
50
  let cursorCol = $state(1);
52
51
  let isUpdating = $state(false);
@@ -91,38 +90,7 @@
91
90
  readonly,
92
91
  });
93
92
 
94
- const slashCommands = useSlashCommands({
95
- getTextareaRef: () => textareaRef,
96
- getContent: () => content,
97
- setContent: (/** @type {string} */ c) => (content = c),
98
- getSnippets: () => snippetsManager.snippets,
99
- onOpenSnippetsModal: () => snippetsManager.openModal(),
100
- });
101
-
102
- // Command palette actions
103
- const basePaletteActions = [
104
- { id: "save", label: "Save", shortcut: "⌘S", action: () => onSave() },
105
- { id: "preview", label: "Toggle Preview", shortcut: "", action: () => (showPreview = !showPreview) },
106
- { id: "fullPreview", label: "Full Preview", shortcut: "", action: () => (showFullPreview = true) },
107
- { id: "zen", label: "Toggle Zen Mode", shortcut: "⌘⇧↵", action: () => toggleZenMode() },
108
- { id: "campfire", label: "Start Campfire Session", shortcut: "", action: () => writingSession.startCampfire() },
109
- { id: "bold", label: "Bold", shortcut: "⌘B", action: () => wrapSelection("**", "**") },
110
- { id: "italic", label: "Italic", shortcut: "⌘I", action: () => wrapSelection("_", "_") },
111
- { id: "code", label: "Insert Code Block", shortcut: "", action: () => insertCodeBlock() },
112
- { id: "link", label: "Insert Link", shortcut: "", action: () => insertLink() },
113
- { id: "image", label: "Insert Image", shortcut: "", action: () => insertImage() },
114
- { id: "goal", label: "Set Writing Goal", shortcut: "", action: () => writingSession.promptWritingGoal() },
115
- { id: "snippets", label: "Manage Snippets", shortcut: "", action: () => snippetsManager.openModal() },
116
- { id: "newSnippet", label: "Create New Snippet", shortcut: "", action: () => snippetsManager.openModal() },
117
- { id: "sounds", label: "Toggle Ambient Sounds", shortcut: "", action: () => ambientSounds.toggle() },
118
- { id: "soundPanel", label: "Sound Settings", shortcut: "", action: () => ambientSounds.togglePanel() },
119
- ];
120
-
121
- const commandPalette = useCommandPalette({
122
- getActions: () => basePaletteActions,
123
- getThemes: () => themes,
124
- getCurrentTheme: () => editorTheme.currentTheme,
125
- });
93
+ // Note: Slash commands and command palette removed for simplified Medium-style UX
126
94
 
127
95
  // Computed values
128
96
  let wordCount = $derived(content.trim() ? content.trim().split(/\s+/).length : 0);
@@ -159,25 +127,6 @@
159
127
  return anchors;
160
128
  });
161
129
 
162
- // Filtered commands for UI
163
- let filteredSlashCommands = $derived.by(() => slashCommands.getFilteredCommands());
164
- let filteredPaletteCommands = $derived.by(() => {
165
- // Include theme actions that actually set the theme
166
- const actions = basePaletteActions.filter((cmd) =>
167
- cmd.label.toLowerCase().includes(commandPalette.query.toLowerCase())
168
- );
169
- const themeCommands = Object.entries(themes)
170
- .filter(([key, theme]) =>
171
- `Theme: ${theme.label} (${theme.desc})`.toLowerCase().includes(commandPalette.query.toLowerCase())
172
- )
173
- .map(([key, theme]) => ({
174
- id: `theme-${key}`,
175
- label: `Theme: ${theme.label} (${theme.desc})`,
176
- shortcut: editorTheme.currentTheme === key ? "●" : "",
177
- action: () => editorTheme.setTheme(key),
178
- }));
179
- return [...actions, ...themeCommands];
180
- });
181
130
 
182
131
  // Public exports
183
132
  export function getAvailableAnchors() {
@@ -207,61 +156,17 @@
207
156
  cursorCol = lines[lines.length - 1].length + 1;
208
157
  }
209
158
 
210
- // Keyboard handlers
159
+ // Keyboard handlers (simplified - removed slash commands and command palette)
211
160
  /** @param {KeyboardEvent} e */
212
161
  function handleKeydown(e) {
213
- // Escape key handling
162
+ // Escape key handling - exit zen mode
214
163
  if (e.key === "Escape") {
215
- if (slashCommands.isOpen) {
216
- slashCommands.close();
217
- return;
218
- }
219
- if (commandPalette.isOpen) {
220
- commandPalette.close();
221
- return;
222
- }
223
164
  if (isZenMode) {
224
165
  isZenMode = false;
225
166
  return;
226
167
  }
227
168
  }
228
169
 
229
- // Slash commands trigger
230
- if (e.key === "/" && !slashCommands.isOpen && textareaRef) {
231
- const pos = textareaRef.selectionStart;
232
- // Only trigger at start of line or after whitespace
233
- if (pos === 0 || /\s$/.test(content.substring(0, pos))) {
234
- setTimeout(() => slashCommands.open(), 0);
235
- }
236
- }
237
-
238
- // Close slash menu on space or enter
239
- if (slashCommands.isOpen && (e.key === " " || e.key === "Enter")) {
240
- if (e.key === "Enter") {
241
- e.preventDefault();
242
- slashCommands.execute(slashCommands.menu.selectedIndex);
243
- }
244
- slashCommands.close();
245
- }
246
-
247
- // Navigate slash menu
248
- if (slashCommands.isOpen) {
249
- if (e.key === "ArrowDown") {
250
- e.preventDefault();
251
- slashCommands.navigate("down");
252
- }
253
- if (e.key === "ArrowUp") {
254
- e.preventDefault();
255
- slashCommands.navigate("up");
256
- }
257
- }
258
-
259
- // Command palette: Cmd+K
260
- if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
261
- e.preventDefault();
262
- commandPalette.toggle();
263
- }
264
-
265
170
  // Zen mode: Cmd+Shift+Enter
266
171
  if (e.key === "Enter" && (e.metaKey || e.ctrlKey) && e.shiftKey) {
267
172
  e.preventDefault();
@@ -558,16 +463,6 @@
558
463
  }
559
464
  }
560
465
 
561
- // Command palette execution
562
- /** @param {number} index */
563
- function executePaletteCommand(index) {
564
- const cmd = filteredPaletteCommands[index];
565
- if (cmd && cmd.action) {
566
- cmd.action();
567
- commandPalette.close();
568
- }
569
- }
570
-
571
466
  onMount(() => {
572
467
  updateCursorPosition();
573
468
  snippetsManager.load();
@@ -642,57 +537,10 @@
642
537
  </div>
643
538
  {/if}
644
539
 
645
- <!-- Toolbar -->
540
+ <!-- Minimal Toolbar (Medium-style - formatting via floating toolbar on selection) -->
646
541
  <div class="toolbar">
647
- <div class="toolbar-group">
648
- <button type="button" class="toolbar-btn" onclick={() => insertHeading(1)} title="Heading 1" disabled={readonly}>
649
- [h<span class="key">1</span>]
650
- </button>
651
- <button type="button" class="toolbar-btn" onclick={() => insertHeading(2)} title="Heading 2" disabled={readonly}>
652
- [h<span class="key">2</span>]
653
- </button>
654
- <button type="button" class="toolbar-btn" onclick={() => insertHeading(3)} title="Heading 3" disabled={readonly}>
655
- [h<span class="key">3</span>]
656
- </button>
657
- </div>
658
-
659
- <div class="toolbar-divider">|</div>
660
-
661
- <div class="toolbar-group">
662
- <button type="button" class="toolbar-btn" onclick={() => wrapSelection("**", "**")} title="Bold (Cmd+B)" disabled={readonly}>
663
- [<span class="key">b</span>old]
664
- </button>
665
- <button type="button" class="toolbar-btn" onclick={() => wrapSelection("_", "_")} title="Italic (Cmd+I)" disabled={readonly}>
666
- [<span class="key">i</span>talic]
667
- </button>
668
- <button type="button" class="toolbar-btn" onclick={() => wrapSelection("`", "`")} title="Inline Code" disabled={readonly}>
669
- [<span class="key">c</span>ode]
670
- </button>
671
- </div>
672
-
673
- <div class="toolbar-divider">|</div>
674
-
675
- <div class="toolbar-group">
676
- <button type="button" class="toolbar-btn" onclick={insertLink} title="Link" disabled={readonly}>
677
- [<span class="key">l</span>ink]
678
- </button>
679
- <button type="button" class="toolbar-btn" onclick={insertImage} title="Image" disabled={readonly}>
680
- [i<span class="key">m</span>g]
681
- </button>
682
- <button type="button" class="toolbar-btn" onclick={insertCodeBlock} title="Code Block" disabled={readonly}>
683
- [bloc<span class="key">k</span>]
684
- </button>
685
- </div>
686
-
687
- <div class="toolbar-divider">|</div>
688
-
689
- <div class="toolbar-group">
690
- <button type="button" class="toolbar-btn" onclick={insertList} title="List" disabled={readonly}>
691
- [lis<span class="key">t</span>]
692
- </button>
693
- <button type="button" class="toolbar-btn" onclick={insertQuote} title="Quote" disabled={readonly}>
694
- [<span class="key">q</span>uote]
695
- </button>
542
+ <div class="toolbar-left">
543
+ <span class="toolbar-hint">Select text to format</span>
696
544
  </div>
697
545
 
698
546
  <div class="toolbar-spacer"></div>
@@ -812,74 +660,13 @@
812
660
  </div>
813
661
  </div>
814
662
 
815
- <!-- Slash Commands Menu -->
816
- {#if slashCommands.isOpen}
817
- <div class="slash-menu">
818
- <div class="slash-menu-header">:: commands</div>
819
- {#each filteredSlashCommands as cmd, i}
820
- <button
821
- type="button"
822
- class="slash-menu-item"
823
- class:selected={i === slashCommands.menu.selectedIndex}
824
- onclick={() => slashCommands.execute(i)}
825
- >
826
- <span class="slash-cmd-label">{cmd.label}</span>
827
- </button>
828
- {/each}
829
- {#if filteredSlashCommands.length === 0}
830
- <div class="slash-menu-empty">; no commands found</div>
831
- {/if}
832
- </div>
833
- {/if}
834
-
835
- <!-- Command Palette -->
836
- {#if commandPalette.isOpen}
837
- <!-- svelte-ignore a11y_no_static_element_interactions a11y_click_events_have_key_events -->
838
- <div class="command-palette-overlay" onclick={() => commandPalette.close()} role="dialog" aria-modal="true" aria-label="Command palette">
839
- <!-- svelte-ignore a11y_no_static_element_interactions a11y_click_events_have_key_events -->
840
- <div class="command-palette" onclick={(e) => e.stopPropagation()}>
841
- <input
842
- type="text"
843
- class="command-palette-input"
844
- placeholder="> type a command..."
845
- value={commandPalette.query}
846
- oninput={(e) => commandPalette.setQuery(/** @type {HTMLInputElement} */ (e.target).value)}
847
- onkeydown={(e) => {
848
- if (e.key === "ArrowDown") {
849
- e.preventDefault();
850
- commandPalette.navigate("down");
851
- }
852
- if (e.key === "ArrowUp") {
853
- e.preventDefault();
854
- commandPalette.navigate("up");
855
- }
856
- if (e.key === "Enter") {
857
- e.preventDefault();
858
- executePaletteCommand(commandPalette.selectedIndex);
859
- }
860
- if (e.key === "Escape") {
861
- commandPalette.close();
862
- }
863
- }}
864
- />
865
- <div class="command-palette-list">
866
- {#each filteredPaletteCommands as cmd, i}
867
- <button
868
- type="button"
869
- class="command-palette-item"
870
- class:selected={i === commandPalette.selectedIndex}
871
- onclick={() => executePaletteCommand(i)}
872
- >
873
- <span class="palette-cmd-label">{cmd.label}</span>
874
- {#if cmd.shortcut}
875
- <span class="palette-cmd-shortcut">{cmd.shortcut}</span>
876
- {/if}
877
- </button>
878
- {/each}
879
- </div>
880
- </div>
881
- </div>
882
- {/if}
663
+ <!-- Floating Toolbar for text formatting (Medium-style) -->
664
+ <FloatingToolbar
665
+ {textareaRef}
666
+ bind:content={content}
667
+ {readonly}
668
+ onContentChange={(c) => content = c}
669
+ />
883
670
 
884
671
  <!-- Campfire Session Controls -->
885
672
  {#if writingSession.isCampfireActive}
@@ -1321,6 +1108,15 @@
1321
1108
  .toolbar-spacer {
1322
1109
  flex: 1;
1323
1110
  }
1111
+ .toolbar-left {
1112
+ display: flex;
1113
+ align-items: center;
1114
+ }
1115
+ .toolbar-hint {
1116
+ color: var(--editor-text-dim, #5a5a5a);
1117
+ font-size: 0.75rem;
1118
+ font-style: italic;
1119
+ }
1324
1120
  .editor-area {
1325
1121
  display: flex;
1326
1122
  flex: 1;
@@ -1657,124 +1453,7 @@
1657
1453
  .campfire-end:hover {
1658
1454
  color: #f0d0a0;
1659
1455
  }
1660
- .slash-menu {
1661
- position: fixed;
1662
- top: 50%;
1663
- left: 50%;
1664
- transform: translate(-50%, -50%);
1665
- min-width: 220px;
1666
- max-height: 300px;
1667
- overflow-y: auto;
1668
- background: #252526;
1669
- border: 1px solid var(--light-border-primary);
1670
- border-radius: 8px;
1671
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
1672
- z-index: 1001;
1673
- animation: scale-in 0.15s ease;
1674
- }
1675
- .slash-menu-header {
1676
- padding: 0.5rem 0.75rem;
1677
- font-size: 0.8rem;
1678
- font-family: "JetBrains Mono", "Fira Code", monospace;
1679
- color: #8bc48b;
1680
- border-bottom: 1px solid var(--light-border-primary);
1681
- }
1682
- .slash-menu-item {
1683
- display: flex;
1684
- align-items: center;
1685
- width: 100%;
1686
- padding: 0.6rem 0.75rem;
1687
- background: transparent;
1688
- border: none;
1689
- color: #d4d4d4;
1690
- font-size: 0.85rem;
1691
- font-family: "JetBrains Mono", "Fira Code", monospace;
1692
- text-align: left;
1693
- cursor: pointer;
1694
- transition: background-color 0.1s ease;
1695
- }
1696
- .slash-menu-item:hover,
1697
- .slash-menu-item.selected {
1698
- background: var(--light-border-primary);
1699
- }
1700
- .slash-menu-item.selected {
1701
- color: #8bc48b;
1702
- }
1703
- .slash-menu-empty {
1704
- padding: 0.75rem;
1705
- color: #7a9a7a;
1706
- font-family: "JetBrains Mono", "Fira Code", monospace;
1707
- font-size: 0.8rem;
1708
- text-align: center;
1709
- }
1710
- .command-palette-overlay {
1711
- position: fixed;
1712
- inset: 0;
1713
- background: rgba(0, 0, 0, 0.5);
1714
- display: flex;
1715
- align-items: flex-start;
1716
- justify-content: center;
1717
- padding-top: 15vh;
1718
- z-index: 1002;
1719
- }
1720
- .command-palette {
1721
- width: 100%;
1722
- max-width: 500px;
1723
- background: var(--light-bg-primary);
1724
- border: 1px solid var(--light-border-primary);
1725
- border-radius: 8px;
1726
- box-shadow: 0 16px 64px rgba(0, 0, 0, 0.6);
1727
- overflow: hidden;
1728
- animation: slide-down 0.2s ease;
1729
- }
1730
- .command-palette-input {
1731
- width: 100%;
1732
- padding: 1rem;
1733
- background: transparent;
1734
- border: none;
1735
- border-bottom: 1px solid var(--light-border-primary);
1736
- color: #d4d4d4;
1737
- font-size: 1rem;
1738
- font-family: "JetBrains Mono", "Fira Code", monospace;
1739
- outline: none;
1740
- }
1741
- .command-palette-input::-moz-placeholder {
1742
- color: #7a9a7a;
1743
- }
1744
- .command-palette-input::placeholder {
1745
- color: #7a9a7a;
1746
- }
1747
- .command-palette-list {
1748
- max-height: 300px;
1749
- overflow-y: auto;
1750
- }
1751
- .command-palette-item {
1752
- display: flex;
1753
- align-items: center;
1754
- justify-content: space-between;
1755
- width: 100%;
1756
- padding: 0.75rem 1rem;
1757
- background: transparent;
1758
- border: none;
1759
- color: #d4d4d4;
1760
- font-size: 0.9rem;
1761
- font-family: "JetBrains Mono", "Fira Code", monospace;
1762
- text-align: left;
1763
- cursor: pointer;
1764
- transition: background-color 0.1s ease;
1765
- }
1766
- .command-palette-item:hover,
1767
- .command-palette-item.selected {
1768
- background: var(--light-bg-tertiary);
1769
- }
1770
- .command-palette-item.selected {
1771
- color: #8bc48b;
1772
- }
1773
- .palette-cmd-shortcut {
1774
- font-size: 0.75rem;
1775
- color: #6a6a6a;
1776
- font-family: "JetBrains Mono", monospace;
1777
- }
1456
+ /* Slash menu and command palette styles removed - using FloatingToolbar instead */
1778
1457
  @keyframes fade-in {
1779
1458
  from { opacity: 0; transform: translateY(10px); }
1780
1459
  to { opacity: 1; transform: translateY(0); }
@@ -27,7 +27,7 @@ declare const MarkdownEditor: import("svelte").Component<{
27
27
  clearDraft: () => void;
28
28
  getDraftStatus: () => {
29
29
  hasDraft: boolean;
30
- storedDraft: import("./composables/useDraftManager.svelte.js").StoredDraft | null;
30
+ storedDraft: import("./composables/useDraftManager.svelte").StoredDraft | null;
31
31
  };
32
32
  }, "content">;
33
33
  type $$ComponentProps = {
@@ -1,7 +1,5 @@
1
1
  export { useSnippets } from "./useSnippets.svelte.js";
2
2
  export { useDraftManager } from "./useDraftManager.svelte.js";
3
3
  export { useWritingSession } from "./useWritingSession.svelte.js";
4
- export { useCommandPalette } from "./useCommandPalette.svelte.js";
5
4
  export { useAmbientSounds, soundLibrary } from "./useAmbientSounds.svelte.js";
6
5
  export { useEditorTheme, themes } from "./useEditorTheme.svelte.js";
7
- export { useSlashCommands, baseSlashCommands } from "./useSlashCommands.svelte.js";
@@ -8,5 +8,3 @@ export { useEditorTheme, themes } from "./useEditorTheme.svelte.js";
8
8
  export { useSnippets } from "./useSnippets.svelte.js";
9
9
  export { useDraftManager } from "./useDraftManager.svelte.js";
10
10
  export { useWritingSession } from "./useWritingSession.svelte.js";
11
- export { useSlashCommands, baseSlashCommands } from "./useSlashCommands.svelte.js";
12
- export { useCommandPalette } from "./useCommandPalette.svelte.js";
@@ -64,7 +64,7 @@
64
64
  * Helper to get anchor key with headers context
65
65
  * @param {string} anchor
66
66
  */
67
- function getKey(anchor) {
67
+ function getKey(anchor: string) {
68
68
  return getAnchorKey(anchor, headers);
69
69
  }
70
70
 
@@ -72,16 +72,16 @@
72
72
  * Get items for a specific anchor
73
73
  * @param {string} anchor
74
74
  */
75
- function getItems(anchor) {
75
+ function getItems(anchor: string) {
76
76
  return getItemsForAnchor(gutterContent, anchor);
77
77
  }
78
78
 
79
79
  /**
80
80
  * Generate unique key for a gutter item
81
- * @param {GutterItem} item
81
+ * @param {GutterItemType} item
82
82
  * @param {number} index
83
83
  */
84
- function getItemKey(item, index) {
84
+ function getItemKey(item: GutterItemType, index: number): string {
85
85
  // Combine item properties to create a unique identifier
86
86
  const parts = [
87
87
  item.type || 'unknown',
@@ -103,16 +103,15 @@
103
103
 
104
104
  // Use getBoundingClientRect for accurate relative positioning
105
105
  // This works regardless of offset parent chains and CSS transforms
106
- const gutterRect = gutterElement.getBoundingClientRect();
106
+ const gutterRect = (gutterElement as HTMLElement).getBoundingClientRect();
107
107
 
108
108
  let lastBottom = 0; // Track the bottom edge of the last positioned item
109
- /** @type {string[]} */
110
- const newOverflowingAnchors = [];
109
+ const newOverflowingAnchors: string[] = [];
111
110
  const newPositions = { ...itemPositions };
112
111
 
113
112
  // Sort anchors by their position in the document
114
113
  const anchorPositions = uniqueAnchors.map(anchor => {
115
- const el = findAnchorElement(anchor, contentBodyElement ?? null, headers);
114
+ const el = findAnchorElement(anchor, (contentBodyElement ?? null) as HTMLElement | null, headers);
116
115
  if (!el && import.meta.env.DEV) {
117
116
  console.warn(`Anchor element not found for: ${anchor}`);
118
117
  }
@@ -168,8 +167,7 @@
168
167
 
169
168
  // Setup resize listener on mount with proper cleanup
170
169
  onMount(() => {
171
- /** @type {ReturnType<typeof setTimeout> | undefined} */
172
- let resizeTimeoutId;
170
+ let resizeTimeoutId: ReturnType<typeof setTimeout> | undefined;
173
171
  const handleResize = () => {
174
172
  clearTimeout(resizeTimeoutId);
175
173
  resizeTimeoutId = setTimeout(() => {
@@ -186,9 +184,8 @@
186
184
 
187
185
  // Setup copy button functionality for code blocks
188
186
  onMount(() => {
189
- /** @param {Event} event */
190
- const handleCopyClick = async (event) => {
191
- const button = /** @type {HTMLElement} */ (event.currentTarget);
187
+ const handleCopyClick = async (event: Event) => {
188
+ const button = event.currentTarget as HTMLElement;
192
189
  const codeText = button.getAttribute('data-code');
193
190
 
194
191
  if (!codeText) return;
@@ -251,20 +248,19 @@
251
248
  // Add IDs to headers and position mobile gutter items
252
249
  $effect(() => {
253
250
  // Track moved elements for cleanup
254
- /** @type {Array<{ element: HTMLElement, originalParent: HTMLElement | null, originalNextSibling: Node | null }>} */
255
- const movedElements = [];
251
+ const movedElements: Array<{ element: HTMLElement; originalParent: HTMLElement | null; originalNextSibling: Node | null }> = [];
256
252
 
257
253
  untrack(() => {
258
254
  if (!contentBodyElement) return;
259
255
 
260
256
  // First, add IDs to headers
261
257
  if (headers && headers.length > 0) {
262
- const headerElements = contentBodyElement.querySelectorAll('h1, h2, h3, h4, h5, h6');
263
- headerElements.forEach((el) => {
264
- const text = el.textContent?.trim() || '';
265
- const matchingHeader = headers.find(/** @param {Header} h */ (h) => h.text === text);
258
+ const headerElements = (contentBodyElement as HTMLElement).querySelectorAll('h1, h2, h3, h4, h5, h6');
259
+ headerElements.forEach((el: Element) => {
260
+ const text = (el as HTMLElement).textContent?.trim() || '';
261
+ const matchingHeader = headers.find((h: Header) => h.text === text);
266
262
  if (matchingHeader) {
267
- el.id = matchingHeader.id;
263
+ (el as HTMLElement).id = matchingHeader.id;
268
264
  }
269
265
  });
270
266
  }
@@ -279,7 +275,7 @@
279
275
  const originalParent = mobileGutterEl.parentElement;
280
276
  const originalNextSibling = mobileGutterEl.nextSibling;
281
277
 
282
- const targetEl = findAnchorElement(anchor, contentBodyElement, headers);
278
+ const targetEl = findAnchorElement(anchor, contentBodyElement as HTMLElement, headers);
283
279
 
284
280
  if (targetEl) {
285
281
  targetEl.insertAdjacentElement('afterend', mobileGutterEl);
@@ -308,12 +304,13 @@
308
304
  const updateHeight = () => {
309
305
  if (!contentBodyElement) return;
310
306
  // Get the bottom of content-body relative to the article
311
- const rect = contentBodyElement.getBoundingClientRect();
312
- const articleRect = contentBodyElement.closest('.content-article')?.getBoundingClientRect();
307
+ const rect = (contentBodyElement as HTMLElement).getBoundingClientRect();
308
+ const articleEl = (contentBodyElement as HTMLElement).closest('.content-article');
309
+ const articleRect = articleEl?.getBoundingClientRect();
313
310
  if (articleRect) {
314
311
  contentHeight = rect.bottom - articleRect.top;
315
312
  } else {
316
- contentHeight = contentBodyElement.offsetTop + contentBodyElement.offsetHeight;
313
+ contentHeight = (contentBodyElement as HTMLElement).offsetTop + (contentBodyElement as HTMLElement).offsetHeight;
317
314
  }
318
315
  };
319
316
  updateHeight();
@@ -348,7 +345,7 @@
348
345
  * @param {string} html
349
346
  * @param {string[]} overflowKeys
350
347
  */
351
- function injectReferenceMarkers(html, overflowKeys) {
348
+ function injectReferenceMarkers(html: string, overflowKeys: string[]): string {
352
349
  if (!overflowKeys || overflowKeys.length === 0 || typeof window === 'undefined') {
353
350
  return html;
354
351
  }