@autumnsgrove/groveengine 0.1.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 (219) hide show
  1. package/README.md +163 -0
  2. package/dist/auth/jwt.d.ts +14 -0
  3. package/dist/auth/jwt.js +109 -0
  4. package/dist/auth/session.d.ts +42 -0
  5. package/dist/auth/session.js +105 -0
  6. package/dist/components/admin/GutterManager.svelte +910 -0
  7. package/dist/components/admin/GutterManager.svelte.d.ts +15 -0
  8. package/dist/components/admin/MarkdownEditor.svelte +3114 -0
  9. package/dist/components/admin/MarkdownEditor.svelte.d.ts +43 -0
  10. package/dist/components/custom/CollapsibleSection.svelte +74 -0
  11. package/dist/components/custom/CollapsibleSection.svelte.d.ts +15 -0
  12. package/dist/components/custom/ContentWithGutter.svelte +646 -0
  13. package/dist/components/custom/ContentWithGutter.svelte.d.ts +19 -0
  14. package/dist/components/custom/GutterItem.svelte +201 -0
  15. package/dist/components/custom/GutterItem.svelte.d.ts +11 -0
  16. package/dist/components/custom/LeftGutter.svelte +271 -0
  17. package/dist/components/custom/LeftGutter.svelte.d.ts +17 -0
  18. package/dist/components/custom/MobileTOC.svelte +273 -0
  19. package/dist/components/custom/MobileTOC.svelte.d.ts +11 -0
  20. package/dist/components/custom/TableOfContents.svelte +163 -0
  21. package/dist/components/custom/TableOfContents.svelte.d.ts +11 -0
  22. package/dist/components/gallery/ImageGallery.svelte +681 -0
  23. package/dist/components/gallery/ImageGallery.svelte.d.ts +11 -0
  24. package/dist/components/gallery/Lightbox.svelte +107 -0
  25. package/dist/components/gallery/Lightbox.svelte.d.ts +19 -0
  26. package/dist/components/gallery/LightboxCaption.svelte +25 -0
  27. package/dist/components/gallery/LightboxCaption.svelte.d.ts +11 -0
  28. package/dist/components/gallery/ZoomableImage.svelte +163 -0
  29. package/dist/components/gallery/ZoomableImage.svelte.d.ts +17 -0
  30. package/dist/components/ui/Accordion.svelte +74 -0
  31. package/dist/components/ui/Accordion.svelte.d.ts +42 -0
  32. package/dist/components/ui/Badge.svelte +48 -0
  33. package/dist/components/ui/Badge.svelte.d.ts +26 -0
  34. package/dist/components/ui/Button.svelte +74 -0
  35. package/dist/components/ui/Button.svelte.d.ts +34 -0
  36. package/dist/components/ui/Card.svelte +102 -0
  37. package/dist/components/ui/Card.svelte.d.ts +46 -0
  38. package/dist/components/ui/Dialog.svelte +91 -0
  39. package/dist/components/ui/Dialog.svelte.d.ts +43 -0
  40. package/dist/components/ui/Input.svelte +81 -0
  41. package/dist/components/ui/Input.svelte.d.ts +35 -0
  42. package/dist/components/ui/Select.svelte +69 -0
  43. package/dist/components/ui/Select.svelte.d.ts +36 -0
  44. package/dist/components/ui/Sheet.svelte +98 -0
  45. package/dist/components/ui/Sheet.svelte.d.ts +45 -0
  46. package/dist/components/ui/Skeleton.svelte +31 -0
  47. package/dist/components/ui/Skeleton.svelte.d.ts +26 -0
  48. package/dist/components/ui/Table.svelte +59 -0
  49. package/dist/components/ui/Table.svelte.d.ts +44 -0
  50. package/dist/components/ui/Tabs.svelte +76 -0
  51. package/dist/components/ui/Tabs.svelte.d.ts +41 -0
  52. package/dist/components/ui/Textarea.svelte +81 -0
  53. package/dist/components/ui/Textarea.svelte.d.ts +35 -0
  54. package/dist/components/ui/Toast.svelte +18 -0
  55. package/dist/components/ui/Toast.svelte.d.ts +7 -0
  56. package/dist/components/ui/accordion/accordion-content.svelte +24 -0
  57. package/dist/components/ui/accordion/accordion-content.svelte.d.ts +4 -0
  58. package/dist/components/ui/accordion/accordion-item.svelte +12 -0
  59. package/dist/components/ui/accordion/accordion-item.svelte.d.ts +4 -0
  60. package/dist/components/ui/accordion/accordion-trigger.svelte +29 -0
  61. package/dist/components/ui/accordion/accordion-trigger.svelte.d.ts +7 -0
  62. package/dist/components/ui/accordion/index.d.ts +6 -0
  63. package/dist/components/ui/accordion/index.js +8 -0
  64. package/dist/components/ui/badge/badge.svelte +50 -0
  65. package/dist/components/ui/badge/badge.svelte.d.ts +60 -0
  66. package/dist/components/ui/badge/index.d.ts +2 -0
  67. package/dist/components/ui/badge/index.js +2 -0
  68. package/dist/components/ui/button/button.svelte +82 -0
  69. package/dist/components/ui/button/button.svelte.d.ts +132 -0
  70. package/dist/components/ui/button/index.d.ts +2 -0
  71. package/dist/components/ui/button/index.js +4 -0
  72. package/dist/components/ui/card/card-content.svelte +16 -0
  73. package/dist/components/ui/card/card-content.svelte.d.ts +5 -0
  74. package/dist/components/ui/card/card-description.svelte +16 -0
  75. package/dist/components/ui/card/card-description.svelte.d.ts +5 -0
  76. package/dist/components/ui/card/card-footer.svelte +16 -0
  77. package/dist/components/ui/card/card-footer.svelte.d.ts +5 -0
  78. package/dist/components/ui/card/card-header.svelte +16 -0
  79. package/dist/components/ui/card/card-header.svelte.d.ts +5 -0
  80. package/dist/components/ui/card/card-title.svelte +25 -0
  81. package/dist/components/ui/card/card-title.svelte.d.ts +8 -0
  82. package/dist/components/ui/card/card.svelte +20 -0
  83. package/dist/components/ui/card/card.svelte.d.ts +5 -0
  84. package/dist/components/ui/card/index.d.ts +7 -0
  85. package/dist/components/ui/card/index.js +9 -0
  86. package/dist/components/ui/dialog/dialog-content.svelte +38 -0
  87. package/dist/components/ui/dialog/dialog-content.svelte.d.ts +9 -0
  88. package/dist/components/ui/dialog/dialog-description.svelte +16 -0
  89. package/dist/components/ui/dialog/dialog-description.svelte.d.ts +4 -0
  90. package/dist/components/ui/dialog/dialog-footer.svelte +20 -0
  91. package/dist/components/ui/dialog/dialog-footer.svelte.d.ts +5 -0
  92. package/dist/components/ui/dialog/dialog-header.svelte +20 -0
  93. package/dist/components/ui/dialog/dialog-header.svelte.d.ts +5 -0
  94. package/dist/components/ui/dialog/dialog-overlay.svelte +19 -0
  95. package/dist/components/ui/dialog/dialog-overlay.svelte.d.ts +4 -0
  96. package/dist/components/ui/dialog/dialog-title.svelte +16 -0
  97. package/dist/components/ui/dialog/dialog-title.svelte.d.ts +4 -0
  98. package/dist/components/ui/dialog/index.d.ts +12 -0
  99. package/dist/components/ui/dialog/index.js +14 -0
  100. package/dist/components/ui/index.d.ts +26 -0
  101. package/dist/components/ui/index.js +29 -0
  102. package/dist/components/ui/input/index.d.ts +2 -0
  103. package/dist/components/ui/input/index.js +4 -0
  104. package/dist/components/ui/input/input.svelte +46 -0
  105. package/dist/components/ui/input/input.svelte.d.ts +13 -0
  106. package/dist/components/ui/select/index.d.ts +11 -0
  107. package/dist/components/ui/select/index.js +13 -0
  108. package/dist/components/ui/select/select-content.svelte +39 -0
  109. package/dist/components/ui/select/select-content.svelte.d.ts +7 -0
  110. package/dist/components/ui/select/select-group-heading.svelte +16 -0
  111. package/dist/components/ui/select/select-group-heading.svelte.d.ts +4 -0
  112. package/dist/components/ui/select/select-item.svelte +37 -0
  113. package/dist/components/ui/select/select-item.svelte.d.ts +4 -0
  114. package/dist/components/ui/select/select-scroll-down-button.svelte +19 -0
  115. package/dist/components/ui/select/select-scroll-down-button.svelte.d.ts +4 -0
  116. package/dist/components/ui/select/select-scroll-up-button.svelte +19 -0
  117. package/dist/components/ui/select/select-scroll-up-button.svelte.d.ts +4 -0
  118. package/dist/components/ui/select/select-separator.svelte +13 -0
  119. package/dist/components/ui/select/select-separator.svelte.d.ts +4 -0
  120. package/dist/components/ui/select/select-trigger.svelte +24 -0
  121. package/dist/components/ui/select/select-trigger.svelte.d.ts +4 -0
  122. package/dist/components/ui/separator/index.d.ts +2 -0
  123. package/dist/components/ui/separator/index.js +4 -0
  124. package/dist/components/ui/separator/separator.svelte +22 -0
  125. package/dist/components/ui/separator/separator.svelte.d.ts +4 -0
  126. package/dist/components/ui/sheet/index.d.ts +12 -0
  127. package/dist/components/ui/sheet/index.js +14 -0
  128. package/dist/components/ui/sheet/sheet-content.svelte +53 -0
  129. package/dist/components/ui/sheet/sheet-content.svelte.d.ts +62 -0
  130. package/dist/components/ui/sheet/sheet-description.svelte +16 -0
  131. package/dist/components/ui/sheet/sheet-description.svelte.d.ts +4 -0
  132. package/dist/components/ui/sheet/sheet-footer.svelte +20 -0
  133. package/dist/components/ui/sheet/sheet-footer.svelte.d.ts +5 -0
  134. package/dist/components/ui/sheet/sheet-header.svelte +20 -0
  135. package/dist/components/ui/sheet/sheet-header.svelte.d.ts +5 -0
  136. package/dist/components/ui/sheet/sheet-overlay.svelte +21 -0
  137. package/dist/components/ui/sheet/sheet-overlay.svelte.d.ts +6 -0
  138. package/dist/components/ui/sheet/sheet-title.svelte +16 -0
  139. package/dist/components/ui/sheet/sheet-title.svelte.d.ts +4 -0
  140. package/dist/components/ui/skeleton/index.d.ts +2 -0
  141. package/dist/components/ui/skeleton/index.js +4 -0
  142. package/dist/components/ui/skeleton/skeleton.svelte +17 -0
  143. package/dist/components/ui/skeleton/skeleton.svelte.d.ts +5 -0
  144. package/dist/components/ui/table/index.d.ts +9 -0
  145. package/dist/components/ui/table/index.js +11 -0
  146. package/dist/components/ui/table/table-body.svelte +16 -0
  147. package/dist/components/ui/table/table-body.svelte.d.ts +5 -0
  148. package/dist/components/ui/table/table-caption.svelte +16 -0
  149. package/dist/components/ui/table/table-caption.svelte.d.ts +5 -0
  150. package/dist/components/ui/table/table-cell.svelte +20 -0
  151. package/dist/components/ui/table/table-cell.svelte.d.ts +5 -0
  152. package/dist/components/ui/table/table-footer.svelte +16 -0
  153. package/dist/components/ui/table/table-footer.svelte.d.ts +5 -0
  154. package/dist/components/ui/table/table-head.svelte +23 -0
  155. package/dist/components/ui/table/table-head.svelte.d.ts +5 -0
  156. package/dist/components/ui/table/table-header.svelte +16 -0
  157. package/dist/components/ui/table/table-header.svelte.d.ts +5 -0
  158. package/dist/components/ui/table/table-row.svelte +23 -0
  159. package/dist/components/ui/table/table-row.svelte.d.ts +5 -0
  160. package/dist/components/ui/table/table.svelte +18 -0
  161. package/dist/components/ui/table/table.svelte.d.ts +5 -0
  162. package/dist/components/ui/tabs/index.d.ts +6 -0
  163. package/dist/components/ui/tabs/index.js +8 -0
  164. package/dist/components/ui/tabs/tabs-content.svelte +19 -0
  165. package/dist/components/ui/tabs/tabs-content.svelte.d.ts +4 -0
  166. package/dist/components/ui/tabs/tabs-list.svelte +19 -0
  167. package/dist/components/ui/tabs/tabs-list.svelte.d.ts +4 -0
  168. package/dist/components/ui/tabs/tabs-trigger.svelte +19 -0
  169. package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +4 -0
  170. package/dist/components/ui/textarea/index.d.ts +2 -0
  171. package/dist/components/ui/textarea/index.js +4 -0
  172. package/dist/components/ui/textarea/textarea.svelte +24 -0
  173. package/dist/components/ui/textarea/textarea.svelte.d.ts +6 -0
  174. package/dist/components/ui/toast.d.ts +86 -0
  175. package/dist/components/ui/toast.js +99 -0
  176. package/dist/db/schema.sql +238 -0
  177. package/dist/index.d.ts +14 -0
  178. package/dist/index.js +20 -0
  179. package/dist/payments/index.d.ts +33 -0
  180. package/dist/payments/index.js +47 -0
  181. package/dist/payments/shop.d.ts +165 -0
  182. package/dist/payments/shop.js +588 -0
  183. package/dist/payments/stripe/client.d.ts +231 -0
  184. package/dist/payments/stripe/client.js +198 -0
  185. package/dist/payments/stripe/index.d.ts +18 -0
  186. package/dist/payments/stripe/index.js +17 -0
  187. package/dist/payments/stripe/provider.d.ts +50 -0
  188. package/dist/payments/stripe/provider.js +530 -0
  189. package/dist/payments/types.d.ts +355 -0
  190. package/dist/payments/types.js +7 -0
  191. package/dist/server/logger.d.ts +53 -0
  192. package/dist/server/logger.js +252 -0
  193. package/dist/styles/content.css +514 -0
  194. package/dist/styles/tokens.css +175 -0
  195. package/dist/utils/api.d.ts +20 -0
  196. package/dist/utils/api.js +109 -0
  197. package/dist/utils/cn.d.ts +15 -0
  198. package/dist/utils/cn.js +18 -0
  199. package/dist/utils/csrf.d.ts +22 -0
  200. package/dist/utils/csrf.js +72 -0
  201. package/dist/utils/debounce.d.ts +7 -0
  202. package/dist/utils/debounce.js +14 -0
  203. package/dist/utils/gallery.d.ts +66 -0
  204. package/dist/utils/gallery.js +181 -0
  205. package/dist/utils/gutter.d.ts +54 -0
  206. package/dist/utils/gutter.js +169 -0
  207. package/dist/utils/imageProcessor.d.ts +58 -0
  208. package/dist/utils/imageProcessor.js +205 -0
  209. package/dist/utils/json.d.ts +17 -0
  210. package/dist/utils/json.js +26 -0
  211. package/dist/utils/markdown.d.ts +101 -0
  212. package/dist/utils/markdown.js +947 -0
  213. package/dist/utils/sanitize.d.ts +25 -0
  214. package/dist/utils/sanitize.js +127 -0
  215. package/dist/utils/validation.d.ts +46 -0
  216. package/dist/utils/validation.js +169 -0
  217. package/dist/utils.d.ts +5 -0
  218. package/dist/utils.js +5 -0
  219. package/package.json +129 -0
@@ -0,0 +1,273 @@
1
+ <script>
2
+ let { headers = [] } = $props();
3
+
4
+ let isOpen = $state(false);
5
+ let menuRef = $state();
6
+ let buttonRef = $state();
7
+ let activeId = $state('');
8
+
9
+ function toggleMenu() {
10
+ isOpen = !isOpen;
11
+ }
12
+
13
+ function closeMenu() {
14
+ isOpen = false;
15
+ }
16
+
17
+ function scrollToHeader(id) {
18
+ const element = document.getElementById(id);
19
+ if (element) {
20
+ element.scrollIntoView({ behavior: 'smooth', block: 'start' });
21
+ // Update URL hash without jumping
22
+ history.pushState(null, '', `#${id}`);
23
+ }
24
+ closeMenu();
25
+ }
26
+
27
+ // Handle click outside
28
+ function handleClickOutside(event) {
29
+ if (isOpen && menuRef && buttonRef) {
30
+ if (!menuRef.contains(event.target) && !buttonRef.contains(event.target)) {
31
+ closeMenu();
32
+ }
33
+ }
34
+ }
35
+
36
+ // Handle escape key
37
+ function handleKeydown(event) {
38
+ if (event.key === 'Escape' && isOpen) {
39
+ closeMenu();
40
+ }
41
+ }
42
+
43
+ // Set up intersection observer to track active section
44
+ function setupScrollTracking() {
45
+ if (typeof window === 'undefined') return;
46
+
47
+ const observer = new IntersectionObserver(
48
+ (entries) => {
49
+ entries.forEach((entry) => {
50
+ if (entry.isIntersecting) {
51
+ activeId = entry.target.id;
52
+ }
53
+ });
54
+ },
55
+ {
56
+ rootMargin: '-20% 0% -35% 0%',
57
+ threshold: 0
58
+ }
59
+ );
60
+
61
+ headers.forEach((header) => {
62
+ const element = document.getElementById(header.id);
63
+ if (element) {
64
+ observer.observe(element);
65
+ }
66
+ });
67
+
68
+ return () => observer.disconnect();
69
+ }
70
+
71
+ $effect(() => {
72
+ const cleanup = setupScrollTracking();
73
+
74
+ // Add event listeners
75
+ document.addEventListener('click', handleClickOutside);
76
+ document.addEventListener('keydown', handleKeydown);
77
+
78
+ return () => {
79
+ if (cleanup) cleanup();
80
+ document.removeEventListener('click', handleClickOutside);
81
+ document.removeEventListener('keydown', handleKeydown);
82
+ };
83
+ });
84
+ </script>
85
+
86
+ {#if headers.length > 0}
87
+ <div class="mobile-toc-wrapper">
88
+ <!-- Floating Button -->
89
+ <button
90
+ bind:this={buttonRef}
91
+ class="toc-button"
92
+ onclick={toggleMenu}
93
+ aria-label="Toggle table of contents"
94
+ aria-expanded={isOpen}
95
+ >
96
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
97
+ <line x1="3" y1="6" x2="21" y2="6"></line>
98
+ <line x1="3" y1="12" x2="15" y2="12"></line>
99
+ <line x1="3" y1="18" x2="18" y2="18"></line>
100
+ </svg>
101
+ </button>
102
+
103
+ <!-- Floating Menu -->
104
+ {#if isOpen}
105
+ <div class="toc-menu" bind:this={menuRef}>
106
+ <h3 class="toc-title">Table of Contents</h3>
107
+ <ul class="toc-list">
108
+ {#each headers as header (header.id)}
109
+ <li
110
+ class="toc-item level-{header.level}"
111
+ class:active={activeId === header.id}
112
+ >
113
+ <button
114
+ type="button"
115
+ onclick={() => scrollToHeader(header.id)}
116
+ class="toc-link"
117
+ >
118
+ {header.text}
119
+ </button>
120
+ </li>
121
+ {/each}
122
+ </ul>
123
+ </div>
124
+ {/if}
125
+ </div>
126
+ {/if}
127
+
128
+ <style>
129
+ .mobile-toc-wrapper {
130
+ display: none;
131
+ position: fixed;
132
+ bottom: 1rem;
133
+ right: 1rem;
134
+ z-index: 1000;
135
+ }
136
+ /* Show only on mobile (tablet and desktop have sidebar TOC) */
137
+ @media (max-width: 768px) {
138
+ .mobile-toc-wrapper {
139
+ display: block;
140
+ }
141
+ }
142
+ .toc-button {
143
+ width: 44px;
144
+ height: 44px;
145
+ border-radius: 50%;
146
+ background: #7c4dab;
147
+ border: none;
148
+ color: white;
149
+ cursor: pointer;
150
+ display: flex;
151
+ align-items: center;
152
+ justify-content: center;
153
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
154
+ transition: background-color 0.2s ease, transform 0.2s ease;
155
+ }
156
+ .toc-button:hover {
157
+ background: #6a3d9a;
158
+ }
159
+ .toc-button:active {
160
+ transform: scale(0.95);
161
+ }
162
+ .toc-menu {
163
+ position: absolute;
164
+ bottom: 52px;
165
+ right: 0;
166
+ width: 280px;
167
+ max-height: 60vh;
168
+ overflow-y: auto;
169
+ background: white;
170
+ border-radius: 8px;
171
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
172
+ padding: 1rem;
173
+ animation: slideIn 0.2s ease;
174
+ }
175
+ :global(.dark) .toc-menu {
176
+ background: var(--light-bg-tertiary);
177
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
178
+ }
179
+ @keyframes slideIn {
180
+ from {
181
+ opacity: 0;
182
+ transform: translateY(8px);
183
+ }
184
+ to {
185
+ opacity: 1;
186
+ transform: translateY(0);
187
+ }
188
+ }
189
+ .toc-title {
190
+ font-size: 0.875rem;
191
+ font-weight: 600;
192
+ text-transform: uppercase;
193
+ letter-spacing: 0.05em;
194
+ color: #666;
195
+ margin: 0 0 1rem 0;
196
+ padding-bottom: 0.5rem;
197
+ border-bottom: 1px solid var(--light-border-primary);
198
+ }
199
+ :global(.dark) .toc-title {
200
+ color: var(--color-text-subtle-dark);
201
+ border-bottom-color: var(--light-border-light);
202
+ }
203
+ .toc-list {
204
+ list-style: none;
205
+ margin: 0;
206
+ padding: 0;
207
+ }
208
+ .toc-item {
209
+ margin: 0;
210
+ padding: 0;
211
+ }
212
+ .toc-link {
213
+ display: block;
214
+ width: 100%;
215
+ text-align: left;
216
+ padding: 0.5rem 0;
217
+ background: none;
218
+ border: none;
219
+ color: #666;
220
+ cursor: pointer;
221
+ transition: color 0.2s ease;
222
+ font-size: 0.875rem;
223
+ font-family: inherit;
224
+ line-height: 1.4;
225
+ }
226
+ .toc-link:hover {
227
+ color: #7c4dab;
228
+ }
229
+ :global(.dark) .toc-link:hover {
230
+ color: #a87ddb;
231
+ }
232
+ .toc-item.active .toc-link {
233
+ color: #7c4dab;
234
+ font-weight: 600;
235
+ }
236
+ :global(.dark) .toc-item.active .toc-link {
237
+ color: #a87ddb;
238
+ }
239
+ /* Indentation based on header level */
240
+ .level-1 .toc-link {
241
+ padding-left: 0;
242
+ font-weight: 600;
243
+ }
244
+ .level-2 .toc-link {
245
+ padding-left: 0;
246
+ }
247
+ .level-3 .toc-link {
248
+ padding-left: 1rem;
249
+ }
250
+ .level-4 .toc-link {
251
+ padding-left: 2rem;
252
+ }
253
+ .level-5 .toc-link {
254
+ padding-left: 3rem;
255
+ }
256
+ .level-6 .toc-link {
257
+ padding-left: 4rem;
258
+ }
259
+ /* Scrollbar styling */
260
+ .toc-menu::-webkit-scrollbar {
261
+ width: 4px;
262
+ }
263
+ .toc-menu::-webkit-scrollbar-track {
264
+ background: transparent;
265
+ }
266
+ .toc-menu::-webkit-scrollbar-thumb {
267
+ background: var(--light-text-secondary);
268
+ border-radius: 2px;
269
+ }
270
+ :global(.dark) .toc-menu::-webkit-scrollbar-thumb {
271
+ background: var(--light-text-secondary);
272
+ }
273
+ </style>
@@ -0,0 +1,11 @@
1
+ export default MobileTOC;
2
+ type MobileTOC = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const MobileTOC: import("svelte").Component<{
7
+ headers?: any[];
8
+ }, {}, "">;
9
+ type $$ComponentProps = {
10
+ headers?: any[];
11
+ };
@@ -0,0 +1,163 @@
1
+ <script>
2
+ let { headers = [] } = $props();
3
+
4
+ let activeId = $state('');
5
+
6
+ // Set up intersection observer to track active section
7
+ function setupScrollTracking() {
8
+ if (typeof window === 'undefined') return;
9
+
10
+ const observer = new IntersectionObserver(
11
+ (entries) => {
12
+ entries.forEach((entry) => {
13
+ if (entry.isIntersecting) {
14
+ activeId = entry.target.id;
15
+ }
16
+ });
17
+ },
18
+ {
19
+ rootMargin: '-20% 0% -35% 0%',
20
+ threshold: 0
21
+ }
22
+ );
23
+
24
+ // Observe all headers in the document
25
+ headers.forEach((header) => {
26
+ const element = document.getElementById(header.id);
27
+ if (element) {
28
+ observer.observe(element);
29
+ }
30
+ });
31
+
32
+ return () => observer.disconnect();
33
+ }
34
+
35
+ // Set up scroll tracking (runs on mount and when headers change)
36
+ $effect(() => {
37
+ const cleanup = setupScrollTracking();
38
+ return cleanup;
39
+ });
40
+
41
+ function scrollToHeader(id) {
42
+ const element = document.getElementById(id);
43
+ if (element) {
44
+ element.scrollIntoView({ behavior: 'smooth', block: 'start' });
45
+ // Update URL hash without jumping
46
+ history.pushState(null, '', `#${id}`);
47
+ }
48
+ }
49
+ </script>
50
+
51
+ {#if headers.length > 0}
52
+ <nav class="toc">
53
+ <h3 class="toc-title">Table of Contents</h3>
54
+ <ul class="toc-list">
55
+ {#each headers as header (header.id)}
56
+ <li
57
+ class="toc-item level-{header.level}"
58
+ class:active={activeId === header.id}
59
+ >
60
+ <button
61
+ type="button"
62
+ onclick={() => scrollToHeader(header.id)}
63
+ class="toc-link"
64
+ >
65
+ {header.text}
66
+ </button>
67
+ </li>
68
+ {/each}
69
+ </ul>
70
+ </nav>
71
+ {/if}
72
+
73
+ <style>
74
+ .toc {
75
+ position: sticky;
76
+ top: 2rem;
77
+ max-height: calc(100vh - 4rem);
78
+ overflow-y: auto;
79
+ padding: 1rem;
80
+ font-size: 0.875rem;
81
+ }
82
+ .toc-title {
83
+ font-size: 0.875rem;
84
+ font-weight: 600;
85
+ text-transform: uppercase;
86
+ letter-spacing: 0.05em;
87
+ color: #666;
88
+ margin: 0 0 1rem 0;
89
+ padding-bottom: 0.5rem;
90
+ border-bottom: 1px solid var(--light-border-primary);
91
+ transition: color 0.3s ease, border-color 0.3s ease;
92
+ }
93
+ .toc-list {
94
+ list-style: none;
95
+ margin: 0;
96
+ padding: 0;
97
+ }
98
+ .toc-item {
99
+ margin: 0;
100
+ padding: 0;
101
+ }
102
+ .toc-link {
103
+ display: block;
104
+ width: 100%;
105
+ text-align: left;
106
+ padding: 0.375rem 0;
107
+ background: none;
108
+ border: none;
109
+ color: #666;
110
+ cursor: pointer;
111
+ transition: color 0.2s ease;
112
+ font-size: inherit;
113
+ font-family: inherit;
114
+ line-height: 1.4;
115
+ }
116
+ .toc-link:hover {
117
+ color: #2c5f2d;
118
+ }
119
+ :global(.dark) .toc-link:hover {
120
+ color: var(--accent-success);
121
+ }
122
+ .toc-item.active .toc-link {
123
+ color: #2c5f2d;
124
+ font-weight: 600;
125
+ }
126
+ :global(.dark) .toc-item.active .toc-link {
127
+ color: var(--accent-success);
128
+ }
129
+ /* Indentation based on header level */
130
+ .level-1 .toc-link {
131
+ padding-left: 0;
132
+ font-weight: 600;
133
+ }
134
+ .level-2 .toc-link {
135
+ padding-left: 0;
136
+ }
137
+ .level-3 .toc-link {
138
+ padding-left: 1rem;
139
+ }
140
+ .level-4 .toc-link {
141
+ padding-left: 2rem;
142
+ }
143
+ .level-5 .toc-link {
144
+ padding-left: 3rem;
145
+ }
146
+ .level-6 .toc-link {
147
+ padding-left: 4rem;
148
+ }
149
+ /* Scrollbar styling */
150
+ .toc::-webkit-scrollbar {
151
+ width: 4px;
152
+ }
153
+ .toc::-webkit-scrollbar-track {
154
+ background: transparent;
155
+ }
156
+ .toc::-webkit-scrollbar-thumb {
157
+ background: var(--light-text-secondary);
158
+ border-radius: 2px;
159
+ }
160
+ :global(.dark) .toc::-webkit-scrollbar-thumb {
161
+ background: var(--light-border-light);
162
+ }
163
+ </style>
@@ -0,0 +1,11 @@
1
+ export default TableOfContents;
2
+ type TableOfContents = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const TableOfContents: import("svelte").Component<{
7
+ headers?: any[];
8
+ }, {}, "">;
9
+ type $$ComponentProps = {
10
+ headers?: any[];
11
+ };