docyard 0.9.0 → 1.0.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 (159) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -0
  3. data/README.md +8 -253
  4. data/exe/docyard +6 -0
  5. data/lib/docyard/build/asset_bundler.rb +2 -2
  6. data/lib/docyard/build/file_copier.rb +12 -5
  7. data/lib/docyard/build/llms_txt_generator.rb +103 -0
  8. data/lib/docyard/build/sitemap_generator.rb +1 -1
  9. data/lib/docyard/build/static_generator.rb +115 -79
  10. data/lib/docyard/builder.rb +6 -2
  11. data/lib/docyard/cli.rb +14 -4
  12. data/lib/docyard/components/processors/callout_processor.rb +1 -1
  13. data/lib/docyard/components/processors/code_block_extended_fence_postprocessor.rb +24 -0
  14. data/lib/docyard/components/processors/code_block_extended_fence_preprocessor.rb +44 -0
  15. data/lib/docyard/components/processors/code_block_options_preprocessor.rb +11 -1
  16. data/lib/docyard/components/processors/code_block_processor.rb +5 -24
  17. data/lib/docyard/components/processors/code_group_processor.rb +6 -22
  18. data/lib/docyard/components/processors/code_snippet_import_preprocessor.rb +1 -0
  19. data/lib/docyard/components/processors/file_tree_processor.rb +1 -2
  20. data/lib/docyard/components/processors/icon_processor.rb +8 -2
  21. data/lib/docyard/components/processors/include_processor.rb +10 -10
  22. data/lib/docyard/components/processors/video_embed_processor.rb +14 -3
  23. data/lib/docyard/components/support/code_block/feature_extractor.rb +3 -1
  24. data/lib/docyard/components/support/code_block/icon_detector.rb +5 -12
  25. data/lib/docyard/components/support/code_block/line_number_resolver.rb +30 -0
  26. data/lib/docyard/components/support/code_detector.rb +2 -12
  27. data/lib/docyard/components/support/code_group/html_builder.rb +2 -6
  28. data/lib/docyard/components/support/tabs/icon_detector.rb +6 -2
  29. data/lib/docyard/components/support/tabs/parser.rb +6 -23
  30. data/lib/docyard/config/analytics_resolver.rb +24 -0
  31. data/lib/docyard/config/branding_resolver.rb +58 -27
  32. data/lib/docyard/config/key_validator.rb +30 -0
  33. data/lib/docyard/config/logo_detector.rb +8 -8
  34. data/lib/docyard/config/schema.rb +39 -0
  35. data/lib/docyard/config/section.rb +21 -0
  36. data/lib/docyard/config/validation_helpers.rb +83 -0
  37. data/lib/docyard/config/validator.rb +45 -144
  38. data/lib/docyard/config/validators/navigation.rb +43 -0
  39. data/lib/docyard/config/validators/section.rb +114 -0
  40. data/lib/docyard/config.rb +46 -102
  41. data/lib/docyard/constants.rb +59 -0
  42. data/lib/docyard/{utils/errors.rb → errors.rb} +6 -0
  43. data/lib/docyard/initializer.rb +100 -49
  44. data/lib/docyard/navigation/page_navigation_builder.rb +65 -0
  45. data/lib/docyard/navigation/sidebar/auto_builder.rb +107 -0
  46. data/lib/docyard/navigation/sidebar/cache.rb +96 -0
  47. data/lib/docyard/navigation/sidebar/config_builder.rb +179 -0
  48. data/lib/docyard/navigation/sidebar/distributed_builder.rb +145 -0
  49. data/lib/docyard/navigation/sidebar/local_config_loader.rb +69 -3
  50. data/lib/docyard/navigation/sidebar/renderer.rb +12 -1
  51. data/lib/docyard/navigation/sidebar_builder.rb +43 -81
  52. data/lib/docyard/rendering/branding_variables.rb +65 -0
  53. data/lib/docyard/rendering/icon_helpers.rb +14 -1
  54. data/lib/docyard/rendering/icons/devicons.rb +63 -0
  55. data/lib/docyard/rendering/icons.rb +26 -27
  56. data/lib/docyard/rendering/markdown.rb +5 -23
  57. data/lib/docyard/rendering/og_helpers.rb +36 -0
  58. data/lib/docyard/rendering/renderer.rb +87 -59
  59. data/lib/docyard/rendering/template_resolver.rb +14 -0
  60. data/lib/docyard/routing/fallback_resolver.rb +3 -3
  61. data/lib/docyard/search/build_indexer.rb +2 -2
  62. data/lib/docyard/search/dev_indexer.rb +36 -28
  63. data/lib/docyard/search/pagefind_support.rb +1 -1
  64. data/lib/docyard/server/asset_handler.rb +39 -15
  65. data/lib/docyard/server/dev_server.rb +90 -55
  66. data/lib/docyard/server/file_watcher.rb +68 -18
  67. data/lib/docyard/server/pagefind_handler.rb +1 -1
  68. data/lib/docyard/server/preview_server.rb +29 -33
  69. data/lib/docyard/server/rack_application.rb +38 -70
  70. data/lib/docyard/server/router.rb +11 -7
  71. data/lib/docyard/server/sse_server.rb +157 -0
  72. data/lib/docyard/server/static_file_app.rb +42 -0
  73. data/lib/docyard/templates/assets/css/components/banner.css +31 -0
  74. data/lib/docyard/templates/assets/css/components/breadcrumbs.css +2 -1
  75. data/lib/docyard/templates/assets/css/components/callout.css +26 -6
  76. data/lib/docyard/templates/assets/css/components/code-block.css +4 -2
  77. data/lib/docyard/templates/assets/css/components/code-group.css +20 -7
  78. data/lib/docyard/templates/assets/css/components/feedback.css +126 -0
  79. data/lib/docyard/templates/assets/css/components/file-tree.css +5 -4
  80. data/lib/docyard/templates/assets/css/components/icon.css +5 -0
  81. data/lib/docyard/templates/assets/css/components/nav-menu.css +20 -4
  82. data/lib/docyard/templates/assets/css/components/navigation.css +25 -3
  83. data/lib/docyard/templates/assets/css/components/page-actions.css +131 -0
  84. data/lib/docyard/templates/assets/css/components/prev-next.css +14 -7
  85. data/lib/docyard/templates/assets/css/components/search.css +6 -10
  86. data/lib/docyard/templates/assets/css/components/tab-bar.css +7 -4
  87. data/lib/docyard/templates/assets/css/components/table-of-contents.css +57 -11
  88. data/lib/docyard/templates/assets/css/components/tabs.css +12 -4
  89. data/lib/docyard/templates/assets/css/components/theme-toggle.css +3 -1
  90. data/lib/docyard/templates/assets/css/landing.css +82 -13
  91. data/lib/docyard/templates/assets/css/layout.css +17 -0
  92. data/lib/docyard/templates/assets/css/markdown.css +22 -2
  93. data/lib/docyard/templates/assets/css/variables.css +13 -1
  94. data/lib/docyard/templates/assets/js/components/code-group.js +4 -1
  95. data/lib/docyard/templates/assets/js/components/copy-page.js +115 -0
  96. data/lib/docyard/templates/assets/js/components/feedback.js +66 -0
  97. data/lib/docyard/templates/assets/js/components/file-tree.js +5 -5
  98. data/lib/docyard/templates/assets/js/components/navigation.js +3 -3
  99. data/lib/docyard/templates/assets/js/components/search.js +3 -3
  100. data/lib/docyard/templates/assets/js/components/table-of-contents.js +12 -6
  101. data/lib/docyard/templates/assets/js/components/tabs.js +45 -22
  102. data/lib/docyard/templates/assets/js/components/tooltip.js +4 -4
  103. data/lib/docyard/templates/assets/js/hot-reload.js +44 -0
  104. data/lib/docyard/templates/errors/404.html.erb +114 -5
  105. data/lib/docyard/templates/errors/500.html.erb +173 -10
  106. data/lib/docyard/templates/init/_sidebar.yml +36 -0
  107. data/lib/docyard/templates/init/docyard.yml +36 -0
  108. data/lib/docyard/templates/init/pages/components.md +146 -0
  109. data/lib/docyard/templates/init/pages/getting-started.md +94 -0
  110. data/lib/docyard/templates/init/pages/index.md +22 -0
  111. data/lib/docyard/templates/layouts/default.html.erb +10 -0
  112. data/lib/docyard/templates/layouts/splash.html.erb +14 -1
  113. data/lib/docyard/templates/partials/_analytics.html.erb +24 -0
  114. data/lib/docyard/templates/partials/_banner.html.erb +1 -1
  115. data/lib/docyard/templates/partials/_code_block.html.erb +1 -1
  116. data/lib/docyard/templates/partials/_feedback.html.erb +14 -0
  117. data/lib/docyard/templates/partials/_footer.html.erb +1 -1
  118. data/lib/docyard/templates/partials/_head.html.erb +79 -4
  119. data/lib/docyard/templates/partials/_icon_library.html.erb +8 -0
  120. data/lib/docyard/templates/partials/_page_actions.html.erb +21 -0
  121. data/lib/docyard/templates/partials/_scripts.html.erb +6 -3
  122. data/lib/docyard/templates/partials/_tabs.html.erb +4 -1
  123. data/lib/docyard/utils/git_info.rb +157 -0
  124. data/lib/docyard/utils/hash_utils.rb +31 -0
  125. data/lib/docyard/utils/html_helpers.rb +8 -0
  126. data/lib/docyard/utils/logging.rb +44 -3
  127. data/lib/docyard/utils/path_resolver.rb +0 -10
  128. data/lib/docyard/utils/path_utils.rb +73 -0
  129. data/lib/docyard/version.rb +1 -1
  130. data/lib/docyard.rb +2 -2
  131. metadata +77 -47
  132. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -31
  133. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  134. data/.github/pull_request_template.md +0 -14
  135. data/.github/workflows/ci.yml +0 -49
  136. data/.rubocop.yml +0 -42
  137. data/CODE_OF_CONDUCT.md +0 -132
  138. data/CONTRIBUTING.md +0 -55
  139. data/LICENSE.vscode-icons +0 -42
  140. data/Rakefile +0 -8
  141. data/lib/docyard/config/constants.rb +0 -31
  142. data/lib/docyard/navigation/sidebar/children_discoverer.rb +0 -51
  143. data/lib/docyard/navigation/sidebar/config_parser.rb +0 -208
  144. data/lib/docyard/navigation/sidebar/file_resolver.rb +0 -90
  145. data/lib/docyard/navigation/sidebar/file_system_scanner.rb +0 -78
  146. data/lib/docyard/navigation/sidebar/metadata_extractor.rb +0 -71
  147. data/lib/docyard/navigation/sidebar/metadata_reader.rb +0 -51
  148. data/lib/docyard/navigation/sidebar/path_prefixer.rb +0 -34
  149. data/lib/docyard/navigation/sidebar/sorter.rb +0 -21
  150. data/lib/docyard/navigation/sidebar/title_extractor.rb +0 -25
  151. data/lib/docyard/navigation/sidebar/tree_builder.rb +0 -140
  152. data/lib/docyard/rendering/icons/LICENSE.phosphor +0 -21
  153. data/lib/docyard/rendering/icons/file_types.rb +0 -79
  154. data/lib/docyard/rendering/icons/phosphor.rb +0 -93
  155. data/lib/docyard/rendering/language_mapping.rb +0 -52
  156. data/lib/docyard/templates/assets/js/reload.js +0 -98
  157. data/lib/docyard/templates/partials/_icon.html.erb +0 -1
  158. data/lib/docyard/templates/partials/_icon_file_extension.html.erb +0 -1
  159. data/sig/docyard.rbs +0 -4
@@ -0,0 +1,126 @@
1
+ .feedback {
2
+ display: flex;
3
+ flex-direction: column;
4
+ align-items: center;
5
+ gap: var(--spacing-3);
6
+ margin-top: var(--spacing-10);
7
+ padding-top: var(--spacing-6);
8
+ }
9
+
10
+ .feedback__question {
11
+ margin: 0;
12
+ font-size: var(--text-sm);
13
+ font-weight: var(--font-medium);
14
+ color: var(--foreground);
15
+ }
16
+
17
+ .feedback__buttons {
18
+ display: flex;
19
+ gap: var(--spacing-2);
20
+ }
21
+
22
+ .feedback__btn {
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ width: 2.5rem;
27
+ height: 2.5rem;
28
+ padding: 0;
29
+ background-color: var(--background);
30
+ border: 1px solid var(--border);
31
+ border-radius: var(--radius-lg);
32
+ color: var(--muted-foreground);
33
+ cursor: pointer;
34
+ transition:
35
+ transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1),
36
+ background-color var(--transition-fast),
37
+ border-color var(--transition-fast),
38
+ color var(--transition-fast),
39
+ box-shadow 0.2s ease;
40
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
41
+ }
42
+
43
+ .feedback__btn:hover {
44
+ background-color: var(--background);
45
+ border-color: var(--foreground);
46
+ color: var(--foreground);
47
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
48
+ }
49
+
50
+ .feedback__btn:active {
51
+ transform: scale(0.92);
52
+ transition:
53
+ transform 0.1s cubic-bezier(0.4, 0, 1, 1),
54
+ background-color var(--transition-fast),
55
+ border-color var(--transition-fast),
56
+ color var(--transition-fast);
57
+ box-shadow: 0 0 1px rgba(0, 0, 0, 0.05);
58
+ }
59
+
60
+ .feedback__btn:focus-visible {
61
+ outline: 2px solid var(--primary);
62
+ outline-offset: 2px;
63
+ }
64
+
65
+ .feedback__btn i[class*="ph-"] {
66
+ font-size: 1.125rem;
67
+ transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
68
+ }
69
+
70
+ .feedback__btn.is-selected {
71
+ background-color: var(--primary);
72
+ border-color: var(--primary);
73
+ color: var(--primary-foreground);
74
+ pointer-events: none;
75
+ }
76
+
77
+ .feedback__btn.is-selected i[class*="ph-"] {
78
+ animation: feedbackPop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
79
+ }
80
+
81
+ .feedback__btn.is-not-selected {
82
+ opacity: 0.4;
83
+ pointer-events: none;
84
+ }
85
+
86
+ @keyframes feedbackPop {
87
+ 0% {
88
+ transform: scale(1);
89
+ }
90
+ 50% {
91
+ transform: scale(1.3);
92
+ }
93
+ 100% {
94
+ transform: scale(1);
95
+ }
96
+ }
97
+
98
+ .feedback__thanks {
99
+ margin: 0;
100
+ font-size: var(--text-sm);
101
+ color: var(--muted-foreground);
102
+ animation: feedbackFadeIn 0.3s ease;
103
+ }
104
+
105
+ .feedback__thanks[hidden] {
106
+ display: none;
107
+ }
108
+
109
+ @keyframes feedbackFadeIn {
110
+ from {
111
+ opacity: 0;
112
+ transform: translateY(-4px);
113
+ }
114
+ to {
115
+ opacity: 1;
116
+ transform: translateY(0);
117
+ }
118
+ }
119
+
120
+ .feedback.is-submitted .feedback__question {
121
+ display: none;
122
+ }
123
+
124
+ .feedback.is-submitted .feedback__buttons {
125
+ display: none;
126
+ }
@@ -51,7 +51,8 @@
51
51
  transition: transform 0.1s cubic-bezier(0.4, 0, 1, 1), background-color 0.1s ease;
52
52
  }
53
53
 
54
- .docyard-filetree__entry .docyard-icon {
54
+ .docyard-filetree__entry .docyard-icon,
55
+ .docyard-filetree__entry i[class*="ph-"] {
55
56
  flex-shrink: 0;
56
57
  display: inline-flex;
57
58
  align-items: center;
@@ -66,12 +67,12 @@
66
67
  height: 100%;
67
68
  }
68
69
 
69
- .docyard-filetree__entry .docyard-icon-folder-open,
70
- .docyard-filetree__entry .docyard-icon-folder {
70
+ .docyard-filetree__entry .ph-folder-open,
71
+ .docyard-filetree__entry .ph-folder {
71
72
  color: var(--muted-foreground);
72
73
  }
73
74
 
74
- .docyard-filetree__entry .docyard-icon-file-text {
75
+ .docyard-filetree__entry .ph-file-text {
75
76
  color: var(--muted-foreground);
76
77
  opacity: 0.6;
77
78
  }
@@ -1,3 +1,8 @@
1
+ i[class*="ph-"] {
2
+ font-size: 1.15em;
3
+ vertical-align: -0.15em;
4
+ }
5
+
1
6
  .docyard-icon {
2
7
  display: inline-flex;
3
8
  align-items: center;
@@ -33,17 +33,23 @@
33
33
  background: var(--background);
34
34
  border-bottom: 1px solid var(--border);
35
35
  z-index: calc(var(--z-dropdown) + 1);
36
- transform: translateY(-8px);
36
+ transform: scale(0.98) translateY(-8px);
37
+ transform-origin: top center;
37
38
  opacity: 0;
38
39
  pointer-events: none;
39
- transition: transform 0.15s ease-out, opacity 0.15s ease-out;
40
+ transition:
41
+ transform 0.15s cubic-bezier(0.4, 0, 0.2, 1),
42
+ opacity 0.12s ease-out;
40
43
  box-shadow: var(--shadow-lg);
41
44
  }
42
45
 
43
46
  .nav-menu-dropdown.is-open {
44
- transform: translateY(0);
47
+ transform: scale(1) translateY(0);
45
48
  opacity: 1;
46
49
  pointer-events: auto;
50
+ transition:
51
+ transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
52
+ opacity 0.15s ease-out;
47
53
  }
48
54
 
49
55
  .nav-menu-content {
@@ -96,7 +102,8 @@
96
102
  opacity: 0.7;
97
103
  }
98
104
 
99
- .nav-menu-item-icon .docyard-icon {
105
+ .nav-menu-item-icon .docyard-icon,
106
+ .nav-menu-item-icon i[class*="ph-"] {
100
107
  width: 18px;
101
108
  height: 18px;
102
109
  }
@@ -225,6 +232,15 @@
225
232
  }
226
233
  }
227
234
 
235
+ /* Adjust dropdown position when announcement banner is visible */
236
+ body.has-announcement .nav-menu-overlay {
237
+ top: calc(var(--header-height) + var(--announcement-height));
238
+ }
239
+
240
+ body.has-announcement .nav-menu-dropdown {
241
+ top: calc(var(--header-height) + var(--announcement-height));
242
+ }
243
+
228
244
  /* Reduced motion preference */
229
245
  @media (prefers-reduced-motion: reduce) {
230
246
  .nav-menu-overlay,
@@ -43,6 +43,10 @@
43
43
  height: 1rem;
44
44
  }
45
45
 
46
+ .nav-section-icon i[class*="ph-"] {
47
+ font-size: 1rem;
48
+ }
49
+
46
50
  .sidebar nav ul {
47
51
  list-style: none;
48
52
  padding: 0;
@@ -242,11 +246,19 @@
242
246
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
243
247
  }
244
248
 
245
- [data-nav-toggle][aria-expanded="true"] .nav-group-icon .docyard-icon {
249
+ .nav-group-icon i[class*="ph-"] {
250
+ display: inline-block;
251
+ font-size: 1rem;
252
+ transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
253
+ }
254
+
255
+ [data-nav-toggle][aria-expanded="true"] .nav-group-icon .docyard-icon,
256
+ [data-nav-toggle][aria-expanded="true"] .nav-group-icon i[class*="ph-"] {
246
257
  transform: rotate(90deg);
247
258
  }
248
259
 
249
- [data-nav-toggle][aria-expanded="false"] .nav-group-icon .docyard-icon {
260
+ [data-nav-toggle][aria-expanded="false"] .nav-group-icon .docyard-icon,
261
+ [data-nav-toggle][aria-expanded="false"] .nav-group-icon i[class*="ph-"] {
250
262
  transition: transform 0.2s cubic-bezier(0.4, 0, 1, 1);
251
263
  }
252
264
 
@@ -302,6 +314,10 @@
302
314
  height: 1rem;
303
315
  }
304
316
 
317
+ .nav-item-icon i[class*="ph-"] {
318
+ font-size: 1rem;
319
+ }
320
+
305
321
  .nav-item-text {
306
322
  flex: 1;
307
323
  min-width: 0;
@@ -322,17 +338,23 @@
322
338
  height: 0.75rem;
323
339
  }
324
340
 
341
+ .nav-item-external i[class*="ph-"] {
342
+ font-size: 0.75rem;
343
+ }
344
+
325
345
  @media (prefers-reduced-motion: reduce) {
326
346
 
327
347
  .sidebar nav a,
328
348
  .nav-group-header,
329
349
  .nav-group-icon .docyard-icon,
350
+ .nav-group-icon i[class*="ph-"],
330
351
  .nav-group-children,
331
352
  .mobile-menu-toggle {
332
353
  transition: none;
333
354
  }
334
355
 
335
- [data-nav-toggle][aria-expanded="true"] .nav-group-icon .docyard-icon {
356
+ [data-nav-toggle][aria-expanded="true"] .nav-group-icon .docyard-icon,
357
+ [data-nav-toggle][aria-expanded="true"] .nav-group-icon i[class*="ph-"] {
336
358
  transform: none;
337
359
  }
338
360
  }
@@ -0,0 +1,131 @@
1
+ .page-actions {
2
+ margin-top: var(--spacing-6);
3
+ padding-top: var(--spacing-4);
4
+ border-top: 1px solid var(--border);
5
+ }
6
+
7
+ .page-actions__copy-btn {
8
+ display: flex;
9
+ align-items: center;
10
+ gap: var(--spacing-2);
11
+ padding: 0;
12
+ background: none;
13
+ border: none;
14
+ font-family: inherit;
15
+ font-size: var(--text-sm);
16
+ color: var(--muted-foreground);
17
+ cursor: pointer;
18
+ transition: color var(--transition-fast);
19
+ }
20
+
21
+ .page-actions__copy-btn:hover {
22
+ color: var(--foreground);
23
+ }
24
+
25
+ .page-actions__copy-btn .docyard-icon,
26
+ .page-actions__copy-btn i[class*="ph-"] {
27
+ font-size: 1rem;
28
+ flex-shrink: 0;
29
+ }
30
+
31
+ .page-actions__copy-btn i[class*="ph-"] {
32
+ display: inline-block;
33
+ transition: transform 0.15s cubic-bezier(0.4, 0, 1, 1);
34
+ }
35
+
36
+ .page-actions__copy-btn.is-copied i[class*="ph-"] {
37
+ color: var(--success, #22c55e);
38
+ }
39
+
40
+ .page-actions__copy-btn.is-copied .page-actions__copy-text {
41
+ color: var(--success, #22c55e);
42
+ }
43
+
44
+ .page-actions__copy-btn i.icon-animate-in {
45
+ animation: iconPopIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
46
+ }
47
+
48
+ .page-actions__copy-btn i.icon-animate-out {
49
+ animation: iconPopOut 0.15s cubic-bezier(0.4, 0, 1, 1);
50
+ }
51
+
52
+ @keyframes iconPopIn {
53
+ 0% {
54
+ transform: scale(0);
55
+ opacity: 0;
56
+ }
57
+ 50% {
58
+ transform: scale(1.2);
59
+ }
60
+ 100% {
61
+ transform: scale(1);
62
+ opacity: 1;
63
+ }
64
+ }
65
+
66
+ @keyframes iconPopOut {
67
+ 0% {
68
+ transform: scale(1);
69
+ opacity: 1;
70
+ }
71
+ 100% {
72
+ transform: scale(0.8);
73
+ opacity: 0;
74
+ }
75
+ }
76
+
77
+ .page-actions__edit-link {
78
+ display: flex;
79
+ align-items: center;
80
+ gap: var(--spacing-2);
81
+ margin-top: var(--spacing-2);
82
+ font-size: var(--text-sm);
83
+ color: var(--muted-foreground);
84
+ text-decoration: none;
85
+ transition: color var(--transition-fast);
86
+ }
87
+
88
+ .page-actions__edit-link:hover {
89
+ color: var(--foreground);
90
+ }
91
+
92
+ .page-actions__edit-link .docyard-icon,
93
+ .page-actions__edit-link i[class*="ph-"] {
94
+ font-size: 1rem;
95
+ flex-shrink: 0;
96
+ }
97
+
98
+ .page-actions__last-updated {
99
+ margin-top: var(--spacing-3);
100
+ font-size: var(--text-xs);
101
+ color: oklch(from var(--muted-foreground) l c h / 80%);
102
+ }
103
+
104
+ .page-actions__last-updated time {
105
+ cursor: help;
106
+ border-bottom: 1px dotted currentColor;
107
+ }
108
+
109
+ .page-actions-mobile {
110
+ display: none;
111
+ }
112
+
113
+ @media (max-width: 1280px) {
114
+ .page-actions-mobile {
115
+ display: block;
116
+ margin-top: var(--spacing-12);
117
+ text-align: center;
118
+ }
119
+
120
+ .page-actions-mobile .page-actions {
121
+ border-top: none;
122
+ padding-top: 0;
123
+ margin-top: 0;
124
+ }
125
+
126
+ .page-actions-mobile .page-actions__copy-btn,
127
+ .page-actions-mobile .page-actions__edit-link {
128
+ width: 100%;
129
+ justify-content: center;
130
+ }
131
+ }
@@ -56,26 +56,31 @@
56
56
  justify-content: flex-end;
57
57
  }
58
58
 
59
- .pager-label .docyard-icon {
59
+ .pager-label .docyard-icon,
60
+ .pager-label i[class*="ph-"] {
60
61
  display: inline-flex;
61
62
  opacity: 0.5;
62
63
  transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
63
64
  }
64
65
 
65
- .pager-label .docyard-icon svg {
66
+ .pager-label .docyard-icon svg,
67
+ .pager-label i[class*="ph-"] {
66
68
  width: 1rem;
67
69
  height: 1rem;
68
70
  }
69
71
 
70
- .pager-link:hover .pager-label .docyard-icon {
72
+ .pager-link:hover .pager-label .docyard-icon,
73
+ .pager-link:hover .pager-label i[class*="ph-"] {
71
74
  opacity: 1;
72
75
  }
73
76
 
74
- .pager-link.prev:hover .pager-label .docyard-icon {
77
+ .pager-link.prev:hover .pager-label .docyard-icon,
78
+ .pager-link.prev:hover .pager-label i[class*="ph-"] {
75
79
  transform: translateX(-4px);
76
80
  }
77
81
 
78
- .pager-link.next:hover .pager-label .docyard-icon {
82
+ .pager-link.next:hover .pager-label .docyard-icon,
83
+ .pager-link.next:hover .pager-label i[class*="ph-"] {
79
84
  transform: translateX(4px);
80
85
  }
81
86
 
@@ -98,7 +103,8 @@
98
103
  padding: var(--spacing-3) var(--spacing-4);
99
104
  }
100
105
 
101
- .pager-label .docyard-icon {
106
+ .pager-label .docyard-icon,
107
+ .pager-label i[class*="ph-"] {
102
108
  opacity: 0.5;
103
109
  }
104
110
 
@@ -110,7 +116,8 @@
110
116
 
111
117
  @media (prefers-reduced-motion: reduce) {
112
118
  .pager-link,
113
- .pager-label .docyard-icon {
119
+ .pager-label .docyard-icon,
120
+ .pager-label i[class*="ph-"] {
114
121
  transition: none;
115
122
  }
116
123
  }
@@ -134,6 +134,7 @@
134
134
  transform: scale(0.95) translateY(-10px);
135
135
  opacity: 0;
136
136
  transition: transform var(--transition-base), opacity var(--transition-fast);
137
+ will-change: transform, opacity;
137
138
  }
138
139
 
139
140
  .search-modal.is-open .search-modal-container {
@@ -247,14 +248,8 @@
247
248
  opacity: 0.4;
248
249
  }
249
250
 
250
- .search-empty-icon .docyard-icon {
251
- width: 4rem;
252
- height: 4rem;
253
- }
254
-
255
- .search-empty-icon .docyard-icon svg {
256
- width: 100%;
257
- height: 100%;
251
+ .search-empty-icon {
252
+ font-size: var(--text-3xl);
258
253
  }
259
254
 
260
255
  .search-empty-title {
@@ -490,7 +485,7 @@
490
485
 
491
486
  @media (max-width: 1024px) {
492
487
 
493
-
488
+
494
489
  .search-trigger {
495
490
  min-width: auto;
496
491
  width: 2.25rem;
@@ -515,7 +510,8 @@
515
510
  display: none;
516
511
  }
517
512
 
518
- .search-trigger-icon .docyard-icon {
513
+ .search-trigger-icon .docyard-icon,
514
+ .search-trigger-icon i[class*="ph-"] {
519
515
  width: 1.25rem;
520
516
  height: 1.25rem;
521
517
  }
@@ -62,7 +62,8 @@
62
62
  opacity: 0.7;
63
63
  }
64
64
 
65
- .tab-icon .docyard-icon {
65
+ .tab-icon .docyard-icon,
66
+ .tab-icon i[class*="ph-"] {
66
67
  width: 16px;
67
68
  height: 16px;
68
69
  }
@@ -89,10 +90,12 @@
89
90
  border-radius: 2px 2px 0 0;
90
91
  pointer-events: none;
91
92
  view-transition-name: tab-indicator;
93
+ opacity: 0;
92
94
  }
93
95
 
94
96
  .tab-indicator.is-ready {
95
- transition: left 0.25s cubic-bezier(0.4, 0, 0.2, 1), width 0.25s cubic-bezier(0.4, 0, 0.2, 1);
97
+ opacity: 1;
98
+ transition: left 0.25s cubic-bezier(0.4, 0, 0.2, 1), width 0.25s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.15s ease;
96
99
  }
97
100
 
98
101
  /* View Transitions API - animate indicator between pages */
@@ -133,9 +136,9 @@
133
136
  top: calc(var(--header-height) + var(--tab-bar-height));
134
137
  }
135
138
 
136
- /* Hide tab bar on mobile */
139
+ /* Hide tab bar on mobile - use .has-tabs for specificity to override .has-tabs .tab-bar { display: block } */
137
140
  @media (max-width: 1024px) {
138
- .tab-bar {
141
+ .has-tabs .tab-bar {
139
142
  display: none;
140
143
  }
141
144
 
@@ -107,12 +107,19 @@
107
107
  box-shadow: 0 0 0 var(--ring-width) oklch(from var(--ring) l c h / 50%);
108
108
  }
109
109
 
110
- .secondary-header-toc-toggle svg {
110
+ .secondary-header-toc-toggle .docyard-icon {
111
111
  transform: rotate(-90deg);
112
112
  transition: transform var(--transition-base);
113
113
  }
114
114
 
115
- .secondary-header-toc-toggle[aria-expanded="true"] svg {
115
+ .secondary-header-toc-toggle i[class*="ph-"] {
116
+ display: inline-block;
117
+ transform: rotate(-90deg);
118
+ transition: transform var(--transition-base);
119
+ }
120
+
121
+ .secondary-header-toc-toggle[aria-expanded="true"] .docyard-icon,
122
+ .secondary-header-toc-toggle[aria-expanded="true"] i[class*="ph-"] {
116
123
  transform: rotate(0deg);
117
124
  }
118
125
  }
@@ -216,7 +223,6 @@
216
223
  }
217
224
 
218
225
  .docyard-toc__nav {
219
- display: none;
220
226
  position: fixed;
221
227
  overflow-y: auto;
222
228
  overscroll-behavior: contain;
@@ -226,19 +232,26 @@
226
232
  border-radius: var(--radius-xl);
227
233
  box-shadow: var(--shadow-lg);
228
234
  z-index: 9999;
229
- transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1),
230
- opacity 0.2s ease,
231
- transform 0.2s ease;
232
- transform: translateY(-8px);
235
+ transform: scale(0.95) translateY(-8px);
236
+ transform-origin: top right;
233
237
  opacity: 0;
238
+ visibility: hidden;
234
239
  pointer-events: none;
240
+ transition:
241
+ transform 0.2s cubic-bezier(0.4, 0, 0.2, 1),
242
+ opacity 0.15s ease-out,
243
+ visibility 0.2s;
235
244
  }
236
245
 
237
246
  .docyard-toc__nav.is-expanded {
238
- display: block;
247
+ transform: scale(1) translateY(0);
239
248
  opacity: 1;
240
- transform: translateY(0);
249
+ visibility: visible;
241
250
  pointer-events: auto;
251
+ transition:
252
+ transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
253
+ opacity 0.2s ease-out,
254
+ visibility 0s;
242
255
  }
243
256
  }
244
257
 
@@ -249,6 +262,11 @@
249
262
  width: 280px;
250
263
  max-height: calc(100vh - var(--header-height) - 3rem - var(--spacing-8));
251
264
  }
265
+
266
+ .has-tabs .docyard-toc__nav {
267
+ top: calc(var(--header-height) + var(--tab-bar-height) + 3rem + var(--spacing-2));
268
+ max-height: calc(100vh - var(--header-height) - var(--tab-bar-height) - 3rem - var(--spacing-8));
269
+ }
252
270
  }
253
271
 
254
272
  @media (max-width: 1024px) {
@@ -257,6 +275,7 @@
257
275
  left: var(--spacing-4);
258
276
  right: var(--spacing-4);
259
277
  max-height: calc(100vh - var(--header-height) - 3rem - var(--spacing-2));
278
+ transform-origin: top center;
260
279
  }
261
280
 
262
281
  .secondary-header.shift-up ~ .layout .docyard-toc__nav {
@@ -270,13 +289,40 @@
270
289
  }
271
290
  }
272
291
 
292
+ /* Adjust TOC dropdown position when announcement banner is visible */
293
+ @media (max-width: 1280px) and (min-width: 1025px) {
294
+ body.has-announcement .docyard-toc__nav {
295
+ top: calc(var(--header-height) + var(--announcement-height) + 3rem + var(--spacing-2));
296
+ max-height: calc(100vh - var(--header-height) - var(--announcement-height) - 3rem - var(--spacing-8));
297
+ }
298
+
299
+ body.has-announcement.has-tabs .docyard-toc__nav {
300
+ top: calc(var(--header-height) + var(--tab-bar-height) + var(--announcement-height) + 3rem + var(--spacing-2));
301
+ max-height: calc(100vh - var(--header-height) - var(--tab-bar-height) - var(--announcement-height) - 3rem - var(--spacing-8));
302
+ }
303
+ }
304
+
305
+ @media (max-width: 1024px) {
306
+ body.has-announcement .docyard-toc__nav {
307
+ top: calc(var(--header-height) + var(--announcement-height) + 3rem - 2px);
308
+ max-height: calc(100vh - var(--header-height) - var(--announcement-height) - 3rem - var(--spacing-2));
309
+ }
310
+
311
+ body.has-announcement .secondary-header.shift-up ~ .layout .docyard-toc__nav {
312
+ top: calc(var(--announcement-height) + 3rem - 2px);
313
+ max-height: calc(100vh - var(--announcement-height) - 3rem - var(--spacing-2));
314
+ }
315
+ }
316
+
273
317
  @media (prefers-reduced-motion: reduce) {
274
318
  .docyard-toc__link,
275
- .docyard-toc__indicator {
319
+ .docyard-toc__indicator,
320
+ .docyard-toc__nav {
276
321
  transition: none;
277
322
  }
278
323
 
279
- .secondary-header-toc-toggle svg {
324
+ .secondary-header-toc-toggle .docyard-icon,
325
+ .secondary-header-toc-toggle i[class*="ph-"] {
280
326
  transition: none;
281
327
  }
282
328
  }