docyard 0.9.0 → 1.0.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 (165) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +57 -1
  3. data/README.md +8 -253
  4. data/exe/docyard +6 -0
  5. data/lib/docyard/build/asset_bundler.rb +24 -2
  6. data/lib/docyard/build/error_page_generator.rb +33 -0
  7. data/lib/docyard/build/file_copier.rb +12 -5
  8. data/lib/docyard/build/file_writer.rb +19 -0
  9. data/lib/docyard/build/llms_txt_generator.rb +103 -0
  10. data/lib/docyard/build/root_fallback_generator.rb +66 -0
  11. data/lib/docyard/build/sitemap_generator.rb +1 -1
  12. data/lib/docyard/build/static_generator.rb +119 -81
  13. data/lib/docyard/builder.rb +6 -2
  14. data/lib/docyard/cli.rb +14 -4
  15. data/lib/docyard/components/processors/callout_processor.rb +1 -1
  16. data/lib/docyard/components/processors/code_block_extended_fence_postprocessor.rb +24 -0
  17. data/lib/docyard/components/processors/code_block_extended_fence_preprocessor.rb +44 -0
  18. data/lib/docyard/components/processors/code_block_options_preprocessor.rb +11 -1
  19. data/lib/docyard/components/processors/code_block_processor.rb +5 -24
  20. data/lib/docyard/components/processors/code_group_processor.rb +6 -22
  21. data/lib/docyard/components/processors/code_snippet_import_preprocessor.rb +1 -0
  22. data/lib/docyard/components/processors/file_tree_processor.rb +1 -2
  23. data/lib/docyard/components/processors/icon_processor.rb +8 -2
  24. data/lib/docyard/components/processors/include_processor.rb +10 -10
  25. data/lib/docyard/components/processors/video_embed_processor.rb +14 -3
  26. data/lib/docyard/components/support/code_block/feature_extractor.rb +3 -1
  27. data/lib/docyard/components/support/code_block/icon_detector.rb +5 -12
  28. data/lib/docyard/components/support/code_block/line_number_resolver.rb +30 -0
  29. data/lib/docyard/components/support/code_detector.rb +2 -12
  30. data/lib/docyard/components/support/code_group/html_builder.rb +2 -6
  31. data/lib/docyard/components/support/tabs/icon_detector.rb +6 -2
  32. data/lib/docyard/components/support/tabs/parser.rb +6 -23
  33. data/lib/docyard/config/analytics_resolver.rb +24 -0
  34. data/lib/docyard/config/branding_resolver.rb +58 -27
  35. data/lib/docyard/config/key_validator.rb +30 -0
  36. data/lib/docyard/config/logo_detector.rb +8 -8
  37. data/lib/docyard/config/schema.rb +39 -0
  38. data/lib/docyard/config/section.rb +21 -0
  39. data/lib/docyard/config/validation_helpers.rb +83 -0
  40. data/lib/docyard/config/validator.rb +45 -144
  41. data/lib/docyard/config/validators/navigation.rb +43 -0
  42. data/lib/docyard/config/validators/section.rb +114 -0
  43. data/lib/docyard/config.rb +46 -102
  44. data/lib/docyard/constants.rb +59 -0
  45. data/lib/docyard/{utils/errors.rb → errors.rb} +6 -0
  46. data/lib/docyard/initializer.rb +100 -49
  47. data/lib/docyard/navigation/breadcrumb_builder.rb +45 -6
  48. data/lib/docyard/navigation/page_navigation_builder.rb +65 -0
  49. data/lib/docyard/navigation/sidebar/auto_builder.rb +107 -0
  50. data/lib/docyard/navigation/sidebar/cache.rb +96 -0
  51. data/lib/docyard/navigation/sidebar/config_builder.rb +179 -0
  52. data/lib/docyard/navigation/sidebar/distributed_builder.rb +145 -0
  53. data/lib/docyard/navigation/sidebar/local_config_loader.rb +69 -3
  54. data/lib/docyard/navigation/sidebar/renderer.rb +12 -1
  55. data/lib/docyard/navigation/sidebar_builder.rb +43 -81
  56. data/lib/docyard/rendering/branding_variables.rb +65 -0
  57. data/lib/docyard/rendering/icon_helpers.rb +14 -1
  58. data/lib/docyard/rendering/icons/devicons.rb +63 -0
  59. data/lib/docyard/rendering/icons.rb +26 -27
  60. data/lib/docyard/rendering/markdown.rb +5 -23
  61. data/lib/docyard/rendering/og_helpers.rb +36 -0
  62. data/lib/docyard/rendering/renderer.rb +96 -61
  63. data/lib/docyard/rendering/template_resolver.rb +14 -0
  64. data/lib/docyard/routing/fallback_resolver.rb +3 -3
  65. data/lib/docyard/search/build_indexer.rb +2 -2
  66. data/lib/docyard/search/dev_indexer.rb +36 -28
  67. data/lib/docyard/search/pagefind_support.rb +1 -1
  68. data/lib/docyard/server/asset_handler.rb +39 -15
  69. data/lib/docyard/server/dev_server.rb +90 -55
  70. data/lib/docyard/server/file_watcher.rb +68 -18
  71. data/lib/docyard/server/pagefind_handler.rb +1 -1
  72. data/lib/docyard/server/preview_server.rb +29 -33
  73. data/lib/docyard/server/rack_application.rb +39 -71
  74. data/lib/docyard/server/router.rb +11 -7
  75. data/lib/docyard/server/sse_server.rb +157 -0
  76. data/lib/docyard/server/static_file_app.rb +42 -0
  77. data/lib/docyard/templates/assets/css/components/banner.css +31 -0
  78. data/lib/docyard/templates/assets/css/components/breadcrumbs.css +2 -1
  79. data/lib/docyard/templates/assets/css/components/callout.css +26 -6
  80. data/lib/docyard/templates/assets/css/components/code-block.css +4 -2
  81. data/lib/docyard/templates/assets/css/components/code-group.css +20 -7
  82. data/lib/docyard/templates/assets/css/components/feedback.css +126 -0
  83. data/lib/docyard/templates/assets/css/components/file-tree.css +5 -4
  84. data/lib/docyard/templates/assets/css/components/heading-anchor.css +2 -2
  85. data/lib/docyard/templates/assets/css/components/icon.css +5 -0
  86. data/lib/docyard/templates/assets/css/components/nav-menu.css +20 -4
  87. data/lib/docyard/templates/assets/css/components/navigation.css +25 -3
  88. data/lib/docyard/templates/assets/css/components/page-actions.css +131 -0
  89. data/lib/docyard/templates/assets/css/components/prev-next.css +14 -7
  90. data/lib/docyard/templates/assets/css/components/search.css +6 -10
  91. data/lib/docyard/templates/assets/css/components/tab-bar.css +9 -6
  92. data/lib/docyard/templates/assets/css/components/table-of-contents.css +63 -17
  93. data/lib/docyard/templates/assets/css/components/tabs.css +12 -4
  94. data/lib/docyard/templates/assets/css/components/theme-toggle.css +3 -1
  95. data/lib/docyard/templates/assets/css/landing.css +82 -13
  96. data/lib/docyard/templates/assets/css/layout.css +32 -16
  97. data/lib/docyard/templates/assets/css/markdown.css +22 -2
  98. data/lib/docyard/templates/assets/css/variables.css +14 -1
  99. data/lib/docyard/templates/assets/js/components/code-group.js +4 -1
  100. data/lib/docyard/templates/assets/js/components/copy-page.js +115 -0
  101. data/lib/docyard/templates/assets/js/components/feedback.js +66 -0
  102. data/lib/docyard/templates/assets/js/components/file-tree.js +5 -5
  103. data/lib/docyard/templates/assets/js/components/navigation.js +3 -3
  104. data/lib/docyard/templates/assets/js/components/search.js +3 -3
  105. data/lib/docyard/templates/assets/js/components/table-of-contents.js +12 -6
  106. data/lib/docyard/templates/assets/js/components/tabs.js +45 -22
  107. data/lib/docyard/templates/assets/js/components/tooltip.js +4 -4
  108. data/lib/docyard/templates/assets/js/hot-reload.js +44 -0
  109. data/lib/docyard/templates/errors/404.html.erb +125 -5
  110. data/lib/docyard/templates/errors/500.html.erb +184 -10
  111. data/lib/docyard/templates/errors/redirect.html.erb +12 -0
  112. data/lib/docyard/templates/init/_sidebar.yml +36 -0
  113. data/lib/docyard/templates/init/docyard.yml +36 -0
  114. data/lib/docyard/templates/init/pages/components.md +146 -0
  115. data/lib/docyard/templates/init/pages/getting-started.md +94 -0
  116. data/lib/docyard/templates/init/pages/index.md +22 -0
  117. data/lib/docyard/templates/layouts/default.html.erb +10 -0
  118. data/lib/docyard/templates/layouts/splash.html.erb +14 -1
  119. data/lib/docyard/templates/partials/_analytics.html.erb +24 -0
  120. data/lib/docyard/templates/partials/_banner.html.erb +1 -1
  121. data/lib/docyard/templates/partials/_code_block.html.erb +1 -1
  122. data/lib/docyard/templates/partials/_feedback.html.erb +14 -0
  123. data/lib/docyard/templates/partials/_footer.html.erb +1 -1
  124. data/lib/docyard/templates/partials/_head.html.erb +80 -5
  125. data/lib/docyard/templates/partials/_icon_library.html.erb +8 -0
  126. data/lib/docyard/templates/partials/_page_actions.html.erb +21 -0
  127. data/lib/docyard/templates/partials/_scripts.html.erb +6 -3
  128. data/lib/docyard/templates/partials/_tabs.html.erb +4 -1
  129. data/lib/docyard/utils/git_info.rb +157 -0
  130. data/lib/docyard/utils/hash_utils.rb +31 -0
  131. data/lib/docyard/utils/html_helpers.rb +8 -0
  132. data/lib/docyard/utils/logging.rb +44 -3
  133. data/lib/docyard/utils/path_resolver.rb +0 -10
  134. data/lib/docyard/utils/path_utils.rb +73 -0
  135. data/lib/docyard/version.rb +1 -1
  136. data/lib/docyard.rb +2 -2
  137. metadata +81 -47
  138. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -31
  139. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  140. data/.github/pull_request_template.md +0 -14
  141. data/.github/workflows/ci.yml +0 -49
  142. data/.rubocop.yml +0 -42
  143. data/CODE_OF_CONDUCT.md +0 -132
  144. data/CONTRIBUTING.md +0 -55
  145. data/LICENSE.vscode-icons +0 -42
  146. data/Rakefile +0 -8
  147. data/lib/docyard/config/constants.rb +0 -31
  148. data/lib/docyard/navigation/sidebar/children_discoverer.rb +0 -51
  149. data/lib/docyard/navigation/sidebar/config_parser.rb +0 -208
  150. data/lib/docyard/navigation/sidebar/file_resolver.rb +0 -90
  151. data/lib/docyard/navigation/sidebar/file_system_scanner.rb +0 -78
  152. data/lib/docyard/navigation/sidebar/metadata_extractor.rb +0 -71
  153. data/lib/docyard/navigation/sidebar/metadata_reader.rb +0 -51
  154. data/lib/docyard/navigation/sidebar/path_prefixer.rb +0 -34
  155. data/lib/docyard/navigation/sidebar/sorter.rb +0 -21
  156. data/lib/docyard/navigation/sidebar/title_extractor.rb +0 -25
  157. data/lib/docyard/navigation/sidebar/tree_builder.rb +0 -140
  158. data/lib/docyard/rendering/icons/LICENSE.phosphor +0 -21
  159. data/lib/docyard/rendering/icons/file_types.rb +0 -79
  160. data/lib/docyard/rendering/icons/phosphor.rb +0 -93
  161. data/lib/docyard/rendering/language_mapping.rb +0 -52
  162. data/lib/docyard/templates/assets/js/reload.js +0 -98
  163. data/lib/docyard/templates/partials/_icon.html.erb +0 -1
  164. data/lib/docyard/templates/partials/_icon_file_extension.html.erb +0 -1
  165. data/sig/docyard.rbs +0 -4
@@ -34,6 +34,7 @@ html:has(.has-tabs) {
34
34
  backdrop-filter: blur(12px);
35
35
  z-index: var(--z-header);
36
36
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
37
+ will-change: transform;
37
38
  }
38
39
 
39
40
  .header.hide-on-scroll {
@@ -178,6 +179,15 @@ html:has(.has-tabs) {
178
179
  display: none;
179
180
  }
180
181
 
182
+ .layout {
183
+ display: flex;
184
+ min-height: calc(100vh - var(--header-height));
185
+ padding-top: var(--header-height);
186
+ width: 100%;
187
+ max-width: var(--layout-max-width);
188
+ margin: 0 auto;
189
+ position: relative;
190
+ }
181
191
 
182
192
  .secondary-header {
183
193
  display: none;
@@ -192,14 +202,15 @@ html:has(.has-tabs) {
192
202
  top: var(--header-height);
193
203
  left: calc(max(0px, (100vw - var(--layout-max-width)) / 2) + var(--sidebar-width));
194
204
  right: max(0px, calc((100vw - var(--layout-max-width)) / 2));
195
- height: 3rem;
196
- min-height: 3rem;
205
+ height: var(--secondary-header-height);
206
+ min-height: var(--secondary-header-height);
197
207
  background: var(--background);
198
208
  border-bottom: 1px solid var(--border);
199
209
  padding: 0 var(--spacing-6);
200
210
  z-index: var(--z-secondary-header);
201
211
  transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1), left 0.3s cubic-bezier(0.4, 0, 0.2, 1);
202
212
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.02);
213
+ will-change: top, left;
203
214
  }
204
215
 
205
216
  .secondary-header.shift-up {
@@ -211,7 +222,7 @@ html:has(.has-tabs) {
211
222
  }
212
223
 
213
224
  .layout {
214
- padding-top: calc(var(--header-height) + 3rem);
225
+ padding-top: calc(var(--header-height) + var(--secondary-header-height));
215
226
  }
216
227
  }
217
228
 
@@ -224,14 +235,15 @@ html:has(.has-tabs) {
224
235
  top: var(--header-height);
225
236
  left: 0;
226
237
  right: 0;
227
- height: 3rem;
228
- min-height: 3rem;
238
+ height: var(--secondary-header-height);
239
+ min-height: var(--secondary-header-height);
229
240
  background: var(--background);
230
241
  border-bottom: 1px solid var(--border);
231
242
  padding: 0 var(--spacing-6);
232
243
  z-index: var(--z-secondary-header);
233
244
  transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
234
245
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.02);
246
+ will-change: top;
235
247
  }
236
248
 
237
249
  .secondary-header.shift-up {
@@ -275,16 +287,6 @@ html:has(.has-tabs) {
275
287
  }
276
288
  }
277
289
 
278
- .layout {
279
- display: flex;
280
- min-height: calc(100vh - var(--header-height));
281
- padding-top: var(--header-height);
282
- width: 100%;
283
- max-width: var(--layout-max-width);
284
- margin: 0 auto;
285
- position: relative;
286
- }
287
-
288
290
  .sidebar {
289
291
  width: var(--sidebar-width);
290
292
  height: calc(100vh - var(--header-height));
@@ -421,7 +423,7 @@ main.content {
421
423
  }
422
424
 
423
425
  .layout {
424
- padding-top: calc(var(--header-height) + 3rem);
426
+ padding-top: calc(var(--header-height) + var(--secondary-header-height));
425
427
  flex-direction: column;
426
428
  }
427
429
 
@@ -715,6 +717,13 @@ main.content {
715
717
 
716
718
  @media (max-width: 1280px) and (min-width: 1025px) {
717
719
  .doc-aside {
720
+ position: absolute;
721
+ width: 0;
722
+ height: 0;
723
+ overflow: visible;
724
+ }
725
+
726
+ .doc-aside .doc-footer-desktop {
718
727
  display: none;
719
728
  }
720
729
 
@@ -736,6 +745,13 @@ main.content {
736
745
 
737
746
  @media (max-width: 1024px) {
738
747
  .doc-aside {
748
+ position: absolute;
749
+ width: 0;
750
+ height: 0;
751
+ overflow: visible;
752
+ }
753
+
754
+ .doc-aside .doc-footer-desktop {
739
755
  display: none;
740
756
  }
741
757
 
@@ -21,6 +21,26 @@
21
21
  font-variant-ligatures: none;
22
22
  }
23
23
 
24
+ .content .docyard-callout--note code:not(.highlight code) {
25
+ background-color: oklch(from var(--callout-note-border) l c h / 15%);
26
+ }
27
+
28
+ .content .docyard-callout--tip code:not(.highlight code) {
29
+ background-color: oklch(from var(--callout-tip-border) l c h / 15%);
30
+ }
31
+
32
+ .content .docyard-callout--important code:not(.highlight code) {
33
+ background-color: oklch(from var(--callout-important-border) l c h / 15%);
34
+ }
35
+
36
+ .content .docyard-callout--warning code:not(.highlight code) {
37
+ background-color: oklch(from var(--callout-warning-border) l c h / 15%);
38
+ }
39
+
40
+ .content .docyard-callout--danger code:not(.highlight code) {
41
+ background-color: oklch(from var(--callout-danger-border) l c h / 15%);
42
+ }
43
+
24
44
  .content ul,
25
45
  .content ol {
26
46
  margin: var(--spacing-5) 0;
@@ -154,7 +174,7 @@
154
174
  cursor: zoom-in;
155
175
  }
156
176
 
157
- .content a:not(.heading-anchor):not(.pager-link):not(.breadcrumb-link):not(.site-footer__link):not(.site-footer__attribution):not(.docyard-card):not(.docyard-announcement__link):not(.docyard-announcement__button) {
177
+ .content a:not(.heading-anchor):not(.pager-link):not(.breadcrumb-link):not(.site-footer__link):not(.site-footer__attribution):not(.docyard-card):not(.docyard-announcement__link):not(.docyard-announcement__button):not(.page-actions__edit-link) {
158
178
  color: var(--foreground);
159
179
  font-weight: var(--font-semibold);
160
180
  text-decoration: none;
@@ -162,7 +182,7 @@
162
182
  transition: border-bottom var(--transition-fast);
163
183
  }
164
184
 
165
- .content a:not(.heading-anchor):not(.pager-link):not(.breadcrumb-link):not(.site-footer__link):not(.site-footer__attribution):not(.docyard-card):not(.docyard-announcement__link):not(.docyard-announcement__button):hover {
185
+ .content a:not(.heading-anchor):not(.pager-link):not(.breadcrumb-link):not(.site-footer__link):not(.site-footer__attribution):not(.docyard-card):not(.docyard-announcement__link):not(.docyard-announcement__button):not(.page-actions__edit-link):hover {
166
186
  border-bottom: 2px solid var(--primary);
167
187
  }
168
188
 
@@ -3,7 +3,7 @@
3
3
  src: url('/_docyard/fonts/Inter-Variable.ttf') format('truetype');
4
4
  font-weight: 100 900;
5
5
  font-style: normal;
6
- font-display: optional;
6
+ font-display: swap;
7
7
  }
8
8
 
9
9
  :root {
@@ -157,6 +157,7 @@
157
157
  --toc-width: 17.5rem;
158
158
  --header-height: 4rem;
159
159
  --tab-bar-height: 3rem;
160
+ --secondary-header-height: 3rem;
160
161
  --content-max-width: 50rem;
161
162
  --layout-max-width: 88rem;
162
163
 
@@ -308,3 +309,15 @@
308
309
  --text-4xl: 1.875rem;
309
310
  }
310
311
  }
312
+
313
+ .no-transition,
314
+ .no-transition *,
315
+ .no-transition *::before,
316
+ .no-transition *::after {
317
+ transition: none !important;
318
+ animation: none !important;
319
+ }
320
+
321
+ .banner-dismissed .docyard-announcement {
322
+ display: none !important;
323
+ }
@@ -59,9 +59,12 @@ class CodeGroup {
59
59
  this.checkIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 256 256"><path d="M229.66,77.66l-128,128a8,8,0,0,1-11.32,0l-56-56a8,8,0,0,1,11.32-11.32L96,188.69,218.34,66.34a8,8,0,0,1,11.32,11.32Z"/></svg>';
60
60
 
61
61
  this.attachEventListeners();
62
- this.updateIndicator();
62
+ this.updateIndicator(false);
63
63
 
64
64
  requestAnimationFrame(() => {
65
+ if (this.indicator) {
66
+ this.indicator.classList.add('is-ready');
67
+ }
65
68
  this.updateScrollIndicators();
66
69
  });
67
70
  }
@@ -0,0 +1,115 @@
1
+ class CopyPageManager {
2
+ constructor() {
3
+ this.buttons = document.querySelectorAll('[data-copy-page]');
4
+ this.markdownElement = document.getElementById('page-markdown');
5
+
6
+ this.handleCopy = this.handleCopy.bind(this);
7
+ this.init();
8
+ }
9
+
10
+ init() {
11
+ if (!this.markdownElement || this.buttons.length === 0) return;
12
+
13
+ this.buttons.forEach(button => {
14
+ button.addEventListener('click', this.handleCopy);
15
+ });
16
+ }
17
+
18
+ getMarkdownContent() {
19
+ if (!this.markdownElement) return null;
20
+
21
+ try {
22
+ return JSON.parse(this.markdownElement.textContent);
23
+ } catch (error) {
24
+ console.warn('Failed to parse markdown content:', error);
25
+ return null;
26
+ }
27
+ }
28
+
29
+ async handleCopy(event) {
30
+ const button = event.currentTarget;
31
+ const content = this.getMarkdownContent();
32
+
33
+ if (!content) {
34
+ console.warn('No markdown content available to copy');
35
+ return;
36
+ }
37
+
38
+ try {
39
+ await this.copyToClipboard(content);
40
+ this.showSuccess(button);
41
+ } catch (error) {
42
+ console.warn('Failed to copy page:', error);
43
+ }
44
+ }
45
+
46
+ async copyToClipboard(text) {
47
+ if (navigator.clipboard && window.isSecureContext) {
48
+ await navigator.clipboard.writeText(text);
49
+ } else {
50
+ this.fallbackCopy(text);
51
+ }
52
+ }
53
+
54
+ fallbackCopy(text) {
55
+ const textArea = document.createElement('textarea');
56
+ textArea.value = text;
57
+ textArea.style.position = 'fixed';
58
+ textArea.style.left = '-999999px';
59
+ textArea.style.top = '-999999px';
60
+ document.body.appendChild(textArea);
61
+ textArea.focus();
62
+ textArea.select();
63
+
64
+ try {
65
+ document.execCommand('copy');
66
+ textArea.remove();
67
+ } catch (error) {
68
+ textArea.remove();
69
+ throw error;
70
+ }
71
+ }
72
+
73
+ showSuccess(button) {
74
+ const iconElement = button.querySelector('i[class*="ph-"]');
75
+ const textElement = button.querySelector('.page-actions__copy-text');
76
+ const originalClasses = iconElement?.className;
77
+
78
+ button.classList.add('is-copied');
79
+
80
+ if (iconElement) {
81
+ iconElement.className = 'ph ph-check';
82
+ iconElement.classList.add('icon-animate-in');
83
+ }
84
+ if (textElement) {
85
+ textElement.textContent = 'Copied';
86
+ }
87
+
88
+ setTimeout(() => {
89
+ button.classList.remove('is-copied');
90
+ if (iconElement && originalClasses) {
91
+ iconElement.classList.add('icon-animate-out');
92
+ setTimeout(() => {
93
+ iconElement.className = originalClasses;
94
+ }, 150);
95
+ }
96
+ if (textElement) {
97
+ textElement.textContent = 'Copy page';
98
+ }
99
+ }, 2000);
100
+ }
101
+ }
102
+
103
+ function initializeCopyPage() {
104
+ new CopyPageManager();
105
+ }
106
+
107
+ if (document.readyState === 'loading') {
108
+ document.addEventListener('DOMContentLoaded', initializeCopyPage);
109
+ } else {
110
+ initializeCopyPage();
111
+ }
112
+
113
+ if (typeof module !== 'undefined' && module.exports) {
114
+ module.exports = { CopyPageManager };
115
+ }
@@ -0,0 +1,66 @@
1
+ class FeedbackManager {
2
+ constructor() {
3
+ this.container = document.querySelector('.feedback');
4
+ if (!this.container) return;
5
+
6
+ this.buttons = this.container.querySelectorAll('.feedback__btn');
7
+ this.thanks = this.container.querySelector('.feedback__thanks');
8
+ this.pagePath = window.location.pathname;
9
+
10
+ this.init();
11
+ }
12
+
13
+ init() {
14
+ this.buttons.forEach(button => {
15
+ button.addEventListener('click', (e) => this.handleFeedback(e));
16
+ });
17
+ }
18
+
19
+ handleFeedback(event) {
20
+ const button = event.currentTarget;
21
+ const value = button.dataset.feedback;
22
+ const isHelpful = value === 'yes';
23
+
24
+ this.updateUI(button);
25
+ this.sendAnalytics(isHelpful);
26
+ }
27
+
28
+ updateUI(selectedButton) {
29
+ this.buttons.forEach(button => {
30
+ if (button === selectedButton) {
31
+ button.classList.add('is-selected');
32
+ } else {
33
+ button.classList.add('is-not-selected');
34
+ }
35
+ });
36
+
37
+ setTimeout(() => {
38
+ this.container.classList.add('is-submitted');
39
+ this.thanks.hidden = false;
40
+ }, 600);
41
+ }
42
+
43
+ sendAnalytics(isHelpful) {
44
+ const helpful = isHelpful ? 'yes' : 'no';
45
+
46
+ if (typeof gtag === 'function') {
47
+ gtag('event', 'page_feedback', {
48
+ feedback_page: this.pagePath,
49
+ helpful: helpful,
50
+ value: isHelpful ? 1 : 0
51
+ });
52
+ }
53
+
54
+ if (typeof plausible === 'function') {
55
+ plausible('Feedback', { props: { helpful: helpful, page: this.pagePath } });
56
+ }
57
+
58
+ if (typeof fathom === 'object' && typeof fathom.trackEvent === 'function') {
59
+ fathom.trackEvent(`feedback_${helpful}`);
60
+ }
61
+ }
62
+ }
63
+
64
+ document.addEventListener('DOMContentLoaded', () => {
65
+ new FeedbackManager();
66
+ });
@@ -17,14 +17,14 @@ function initializeFileTrees() {
17
17
 
18
18
  folder.classList.toggle('docyard-filetree__item--collapsed');
19
19
 
20
- const icon = entry.querySelector('.docyard-icon');
20
+ const icon = entry.querySelector('i[class*="ph-"]');
21
21
  if (icon) {
22
22
  if (isCollapsed) {
23
- icon.classList.remove('docyard-icon-folder');
24
- icon.classList.add('docyard-icon-folder-open');
23
+ icon.classList.remove('ph-folder');
24
+ icon.classList.add('ph-folder-open');
25
25
  } else {
26
- icon.classList.remove('docyard-icon-folder-open');
27
- icon.classList.add('docyard-icon-folder');
26
+ icon.classList.remove('ph-folder-open');
27
+ icon.classList.add('ph-folder');
28
28
  }
29
29
  }
30
30
  });
@@ -267,7 +267,7 @@
267
267
  scrollTimeout = setTimeout(function() {
268
268
  sessionStorage.setItem(STORAGE_KEY, scrollContainer.scrollTop);
269
269
  }, 150);
270
- });
270
+ }, { passive: true });
271
271
 
272
272
  const logo = document.querySelector('.header-logo');
273
273
  if (logo) {
@@ -304,9 +304,9 @@
304
304
 
305
305
  updateFadeIndicators();
306
306
 
307
- scrollContainer.addEventListener('scroll', updateFadeIndicators);
307
+ scrollContainer.addEventListener('scroll', updateFadeIndicators, { passive: true });
308
308
 
309
- window.addEventListener('resize', updateFadeIndicators);
309
+ window.addEventListener('resize', updateFadeIndicators, { passive: true });
310
310
  }
311
311
 
312
312
  function initScrollBehavior() {
@@ -220,11 +220,11 @@ class SearchManager {
220
220
 
221
221
  async initPagefind() {
222
222
  try {
223
- this.pagefind = await import('/pagefind/pagefind.js');
224
- await this.pagefind.init();
223
+ this.pagefind = await import('/_docyard/pagefind/pagefind.js');
224
+ await this.pagefind.options({ baseUrl: '/' });
225
225
  } catch (error) {
226
226
  console.warn('Pagefind not available:', error);
227
- this.showErrorState('Search is not available. Run "docyard build" to generate the search index.');
227
+ this.showErrorState('Search is not available. Run "docyard serve -s" to enable search.');
228
228
  }
229
229
  }
230
230
 
@@ -308,7 +308,7 @@ class TableOfContentsManager {
308
308
  };
309
309
 
310
310
  checkOverflow();
311
- window.addEventListener('resize', checkOverflow);
311
+ window.addEventListener('resize', checkOverflow, { passive: true });
312
312
  }
313
313
 
314
314
  setupScrollFadeIndicators() {
@@ -343,11 +343,11 @@ class TableOfContentsManager {
343
343
  scrollContainer.addEventListener('scroll', () => {
344
344
  updateFadeIndicators();
345
345
  this.updateIndicator();
346
- });
346
+ }, { passive: true });
347
347
  window.addEventListener('resize', () => {
348
348
  updateFadeIndicators();
349
349
  this.updateIndicator();
350
- });
350
+ }, { passive: true });
351
351
  }
352
352
 
353
353
 
@@ -375,10 +375,16 @@ class TableOfContentsManager {
375
375
  }
376
376
  }
377
377
 
378
+ function initializeTableOfContents() {
379
+ window.tocManager = new TableOfContentsManager();
380
+ }
381
+
378
382
  if (typeof window !== 'undefined') {
379
- document.addEventListener('DOMContentLoaded', () => {
380
- window.tocManager = new TableOfContentsManager();
381
- });
383
+ if (document.readyState === 'loading') {
384
+ document.addEventListener('DOMContentLoaded', initializeTableOfContents);
385
+ } else {
386
+ initializeTableOfContents();
387
+ }
382
388
 
383
389
  window.addEventListener('beforeunload', () => {
384
390
  if (window.tocManager) {
@@ -16,6 +16,7 @@ class TabsManager {
16
16
  this.handleKeyDown = this.handleKeyDown.bind(this);
17
17
  this.handleResize = this.handleResize.bind(this);
18
18
  this.handleScroll = this.handleScroll.bind(this);
19
+ this.handleTabSync = this.handleTabSync.bind(this);
19
20
 
20
21
  this.init();
21
22
  }
@@ -30,9 +31,12 @@ class TabsManager {
30
31
  this.loadPreference();
31
32
  this.attachEventListeners();
32
33
  this.activateTab(this.activeIndex, false);
33
- this.updateIndicator();
34
+ this.updateIndicator(false);
34
35
 
35
36
  requestAnimationFrame(() => {
37
+ if (this.indicator) {
38
+ this.indicator.classList.add('is-ready');
39
+ }
36
40
  requestAnimationFrame(() => {
37
41
  this.updateScrollIndicators();
38
42
  });
@@ -63,6 +67,8 @@ class TabsManager {
63
67
  this.tabList.addEventListener('scroll', this.handleScroll);
64
68
 
65
69
  window.addEventListener('resize', this.handleResize);
70
+
71
+ window.addEventListener('docyard-tab-change', this.handleTabSync);
66
72
  }
67
73
 
68
74
 
@@ -70,7 +76,36 @@ class TabsManager {
70
76
  if (index === this.activeIndex) return;
71
77
 
72
78
  this.activateTab(index, true);
73
- this.savePreference(index);
79
+ this.broadcastTabChange(index);
80
+ }
81
+
82
+ handleTabSync(event) {
83
+ if (event.detail.sourceId === this.groupId) return;
84
+
85
+ const tabName = event.detail.tabName;
86
+ const index = this.tabs.findIndex(tab =>
87
+ tab.getAttribute('data-tab-name') === tabName
88
+ );
89
+
90
+ if (index !== -1 && index !== this.activeIndex) {
91
+ this.activateTab(index, true);
92
+ }
93
+ }
94
+
95
+ broadcastTabChange(index) {
96
+ if (index < 0 || index >= this.tabs.length) return;
97
+
98
+ const tabName = this.tabs[index].getAttribute('data-tab-name');
99
+
100
+ try {
101
+ localStorage.setItem('docyard-preferred-pm', tabName);
102
+ } catch (error) {
103
+ // Silently fail if localStorage is unavailable
104
+ }
105
+
106
+ window.dispatchEvent(new CustomEvent('docyard-tab-change', {
107
+ detail: { tabName, sourceId: this.groupId }
108
+ }));
74
109
  }
75
110
 
76
111
 
@@ -92,6 +127,7 @@ class TabsManager {
92
127
  if (key === 'Home') {
93
128
  event.preventDefault();
94
129
  this.activateTab(0, true);
130
+ this.broadcastTabChange(0);
95
131
  this.tabs[0].focus();
96
132
  }
97
133
 
@@ -99,6 +135,7 @@ class TabsManager {
99
135
  event.preventDefault();
100
136
  const lastIndex = this.tabs.length - 1;
101
137
  this.activateTab(lastIndex, true);
138
+ this.broadcastTabChange(lastIndex);
102
139
  this.tabs[lastIndex].focus();
103
140
  }
104
141
  }
@@ -153,22 +190,20 @@ class TabsManager {
153
190
  });
154
191
 
155
192
  this.updateIndicator(animate);
156
-
157
- if (previousIndex !== index) {
158
- this.savePreference(index);
159
- }
160
193
  }
161
194
 
162
195
 
163
196
  activateNextTab() {
164
197
  const nextIndex = (this.activeIndex + 1) % this.tabs.length;
165
198
  this.activateTab(nextIndex, true);
199
+ this.broadcastTabChange(nextIndex);
166
200
  }
167
201
 
168
-
202
+
169
203
  activatePreviousTab() {
170
204
  const prevIndex = (this.activeIndex - 1 + this.tabs.length) % this.tabs.length;
171
205
  this.activateTab(prevIndex, true);
206
+ this.broadcastTabChange(prevIndex);
172
207
  }
173
208
 
174
209
 
@@ -227,7 +262,7 @@ class TabsManager {
227
262
  if (!preferredTab) return;
228
263
 
229
264
  const index = this.tabs.findIndex(tab =>
230
- tab.textContent.trim().toLowerCase() === preferredTab.toLowerCase()
265
+ tab.getAttribute('data-tab-name') === preferredTab
231
266
  );
232
267
 
233
268
  if (index !== -1) {
@@ -238,22 +273,9 @@ class TabsManager {
238
273
  }
239
274
  }
240
275
 
241
-
242
- savePreference(index) {
243
- if (index < 0 || index >= this.tabs.length) return;
244
-
245
- try {
246
- const tabName = this.tabs[index].textContent.trim().toLowerCase();
247
- localStorage.setItem('docyard-preferred-pm', tabName);
248
- } catch (error) {
249
- console.warn('Could not save tab preference:', error);
250
- }
251
- }
252
-
253
-
254
276
  activateTabByName(name) {
255
277
  const index = this.tabs.findIndex(tab =>
256
- tab.textContent.trim().toLowerCase() === name.toLowerCase()
278
+ tab.getAttribute('data-tab-name') === name.toLowerCase()
257
279
  );
258
280
 
259
281
  if (index !== -1) {
@@ -270,6 +292,7 @@ class TabsManager {
270
292
  this.tabList.removeEventListener('keydown', this.handleKeyDown);
271
293
  this.tabList.removeEventListener('scroll', this.handleScroll);
272
294
  window.removeEventListener('resize', this.handleResize);
295
+ window.removeEventListener('docyard-tab-change', this.handleTabSync);
273
296
 
274
297
  if (this.resizeTimeout) {
275
298
  cancelAnimationFrame(this.resizeTimeout);
@@ -11,20 +11,20 @@ function initializeTooltips() {
11
11
  popover.addEventListener('mouseenter', () => {
12
12
  isHoveringPopover = true;
13
13
  clearTimeout(hideTimeout);
14
- });
14
+ }, { passive: true });
15
15
 
16
16
  popover.addEventListener('mouseleave', () => {
17
17
  isHoveringPopover = false;
18
18
  hideTimeout = setTimeout(() => {
19
19
  hideTooltipPopover(popover);
20
20
  }, 100);
21
- });
21
+ }, { passive: true });
22
22
 
23
23
  tooltips.forEach(tooltip => {
24
24
  tooltip.addEventListener('mouseenter', () => {
25
25
  clearTimeout(hideTimeout);
26
26
  showTooltipPopover(popover, tooltip);
27
- });
27
+ }, { passive: true });
28
28
 
29
29
  tooltip.addEventListener('mouseleave', () => {
30
30
  hideTimeout = setTimeout(() => {
@@ -32,7 +32,7 @@ function initializeTooltips() {
32
32
  hideTooltipPopover(popover);
33
33
  }
34
34
  }, 100);
35
- });
35
+ }, { passive: true });
36
36
  });
37
37
  }
38
38