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
@@ -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 */
@@ -120,7 +123,7 @@
120
123
 
121
124
  @media (max-width: 1280px) and (min-width: 1025px) {
122
125
  .has-tabs .layout {
123
- padding-top: calc(var(--header-height) + var(--tab-bar-height) + 3rem);
126
+ padding-top: calc(var(--header-height) + var(--tab-bar-height) + var(--secondary-header-height));
124
127
  }
125
128
  }
126
129
 
@@ -133,14 +136,14 @@
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
 
142
145
  .has-tabs .layout {
143
- padding-top: calc(var(--header-height) + 3rem);
146
+ padding-top: calc(var(--header-height) + var(--secondary-header-height));
144
147
  }
145
148
 
146
149
  .has-tabs .sidebar {
@@ -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,42 +232,55 @@
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
 
245
258
  @media (max-width: 1280px) and (min-width: 1025px) {
246
259
  .docyard-toc__nav {
247
- top: calc(var(--header-height) + 3rem + var(--spacing-2));
260
+ top: calc(var(--header-height) + var(--secondary-header-height) + var(--spacing-2));
248
261
  right: var(--spacing-6);
249
262
  width: 280px;
250
- max-height: calc(100vh - var(--header-height) - 3rem - var(--spacing-8));
263
+ max-height: calc(100vh - var(--header-height) - var(--secondary-header-height) - var(--spacing-8));
264
+ }
265
+
266
+ .has-tabs .docyard-toc__nav {
267
+ top: calc(var(--header-height) + var(--tab-bar-height) + var(--secondary-header-height) + var(--spacing-2));
268
+ max-height: calc(100vh - var(--header-height) - var(--tab-bar-height) - var(--secondary-header-height) - var(--spacing-8));
251
269
  }
252
270
  }
253
271
 
254
272
  @media (max-width: 1024px) {
255
273
  .docyard-toc__nav {
256
- top: calc(var(--header-height) + 3rem - 2px);
274
+ top: calc(var(--header-height) + var(--secondary-header-height) - 2px);
257
275
  left: var(--spacing-4);
258
276
  right: var(--spacing-4);
259
- max-height: calc(100vh - var(--header-height) - 3rem - var(--spacing-2));
277
+ max-height: calc(100vh - var(--header-height) - var(--secondary-header-height) - var(--spacing-2));
278
+ transform-origin: top center;
260
279
  }
261
280
 
262
281
  .secondary-header.shift-up ~ .layout .docyard-toc__nav {
263
- top: calc(3rem - 2px);
264
- max-height: calc(100vh - 3rem - var(--spacing-2));
282
+ top: calc(var(--secondary-header-height) - 2px);
283
+ max-height: calc(100vh - var(--secondary-header-height) - var(--spacing-2));
265
284
  }
266
285
 
267
286
  .docyard-toc__list .docyard-toc__list {
@@ -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) + var(--secondary-header-height) + var(--spacing-2));
296
+ max-height: calc(100vh - var(--header-height) - var(--announcement-height) - var(--secondary-header-height) - 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) + var(--secondary-header-height) + var(--spacing-2));
301
+ max-height: calc(100vh - var(--header-height) - var(--tab-bar-height) - var(--announcement-height) - var(--secondary-header-height) - 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) + var(--secondary-header-height) - 2px);
308
+ max-height: calc(100vh - var(--header-height) - var(--announcement-height) - var(--secondary-header-height) - var(--spacing-2));
309
+ }
310
+
311
+ body.has-announcement .secondary-header.shift-up ~ .layout .docyard-toc__nav {
312
+ top: calc(var(--announcement-height) + var(--secondary-header-height) - 2px);
313
+ max-height: calc(100vh - var(--announcement-height) - var(--secondary-header-height) - 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
  }
@@ -74,7 +74,8 @@
74
74
  flex-shrink: 0;
75
75
  }
76
76
 
77
- .docyard-tabs__icon .docyard-icon {
77
+ .docyard-tabs__icon .docyard-icon,
78
+ .docyard-tabs__icon i[class*="ph-"] {
78
79
  width: 1rem;
79
80
  height: 1rem;
80
81
  display: inline-flex;
@@ -94,13 +95,19 @@
94
95
  border-radius: 1px;
95
96
  pointer-events: none;
96
97
  z-index: 1;
97
-
98
+ opacity: 0;
99
+
98
100
  transition:
99
101
  transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1),
100
- width 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
102
+ width 0.3s cubic-bezier(0.34, 1.56, 0.64, 1),
103
+ opacity 0.15s ease;
101
104
  will-change: transform, width;
102
105
  }
103
106
 
107
+ .docyard-tabs__indicator.is-ready {
108
+ opacity: 1;
109
+ }
110
+
104
111
  .docyard-tabs__scroll-indicator {
105
112
  position: absolute;
106
113
  top: 0;
@@ -230,7 +237,8 @@
230
237
  gap: var(--spacing-1);
231
238
  }
232
239
 
233
- .docyard-tabs__icon .docyard-icon {
240
+ .docyard-tabs__icon .docyard-icon,
241
+ .docyard-tabs__icon i[class*="ph-"] {
234
242
  width: 0.875rem;
235
243
  height: 0.875rem;
236
244
  }
@@ -39,7 +39,9 @@
39
39
  }
40
40
 
41
41
  .theme-toggle-sun .docyard-icon,
42
- .theme-toggle-moon .docyard-icon {
42
+ .theme-toggle-moon .docyard-icon,
43
+ .theme-toggle-sun i[class*="ph-"],
44
+ .theme-toggle-moon i[class*="ph-"] {
43
45
  width: 1.125rem;
44
46
  height: 1.125rem;
45
47
  }
@@ -73,15 +73,15 @@
73
73
 
74
74
  .hero-bg--grid {
75
75
  background-image:
76
- linear-gradient(oklch(0 0 0 / 0.06) 1px, transparent 1px),
77
- linear-gradient(90deg, oklch(0 0 0 / 0.06) 1px, transparent 1px);
78
- background-size: 100px 100px;
76
+ linear-gradient(oklch(0 0 0 / 0.03) 1px, transparent 1px),
77
+ linear-gradient(90deg, oklch(0 0 0 / 0.03) 1px, transparent 1px);
78
+ background-size: 60px 60px;
79
79
  }
80
80
 
81
81
  .dark .hero-bg--grid {
82
82
  background-image:
83
- linear-gradient(oklch(1 0 0 / 0.08) 1px, transparent 1px),
84
- linear-gradient(90deg, oklch(1 0 0 / 0.08) 1px, transparent 1px);
83
+ linear-gradient(oklch(1 0 0 / 0.04) 1px, transparent 1px),
84
+ linear-gradient(90deg, oklch(1 0 0 / 0.04) 1px, transparent 1px);
85
85
  }
86
86
 
87
87
  .hero-bg--grid::after {
@@ -249,7 +249,7 @@
249
249
  background: linear-gradient(135deg,
250
250
  var(--foreground) 0%,
251
251
  var(--foreground) 40%,
252
- oklch(from var(--primary) calc(l + 0.1) c h) 100%);
252
+ oklch(from var(--primary) calc(l - 0.15) c h) 100%);
253
253
  -webkit-background-clip: text;
254
254
  -webkit-text-fill-color: transparent;
255
255
  background-clip: text;
@@ -314,12 +314,12 @@
314
314
 
315
315
  .hero-action--secondary {
316
316
  background: transparent;
317
- color: var(--foreground);
318
- border: 1px solid var(--border);
317
+ color: var(--muted-foreground);
318
+ border: none;
319
319
  }
320
320
 
321
321
  .hero-action--secondary:hover {
322
- background: var(--muted);
322
+ background: transparent;
323
323
  color: var(--foreground);
324
324
  }
325
325
 
@@ -382,6 +382,70 @@
382
382
  display: block;
383
383
  }
384
384
 
385
+ .hero-custom-visual {
386
+ position: relative;
387
+ z-index: 1;
388
+ }
389
+
390
+ .hero-custom-visual--side {
391
+ display: flex;
392
+ align-items: center;
393
+ justify-content: center;
394
+ }
395
+
396
+ .hero-custom-visual--bottom {
397
+ width: 100%;
398
+ max-width: 1100px;
399
+ margin: 0 auto;
400
+ padding: 0 var(--spacing-6);
401
+ margin-bottom: var(--spacing-2);
402
+ }
403
+
404
+ .hero--with-bottom-visual {
405
+ min-height: auto;
406
+ height: auto;
407
+ align-items: flex-start;
408
+ padding-top: 10rem;
409
+ padding-bottom: var(--spacing-4);
410
+ }
411
+
412
+ .hero--with-bottom-visual .hero-content {
413
+ padding-top: 0;
414
+ padding-bottom: var(--spacing-16);
415
+ }
416
+
417
+ @media (max-width: 1024px) {
418
+ .hero-custom-visual--side {
419
+ grid-column: 1 / -1;
420
+ order: 1;
421
+ width: 100%;
422
+ max-width: 1100px;
423
+ margin: 0 auto;
424
+ padding: 0 var(--spacing-4);
425
+ margin-bottom: var(--spacing-2);
426
+ }
427
+
428
+ .hero--with-image:has(.hero-custom-visual--side) {
429
+ min-height: auto;
430
+ height: auto;
431
+ padding-top: 7rem;
432
+ padding-bottom: var(--spacing-4);
433
+ }
434
+
435
+ .hero--with-image:has(.hero-custom-visual--side) .hero-content {
436
+ padding-top: 0;
437
+ padding-bottom: var(--spacing-16);
438
+ }
439
+
440
+ .hero-custom-visual--bottom {
441
+ padding: 0 var(--spacing-4);
442
+ }
443
+
444
+ .hero--with-bottom-visual {
445
+ padding-top: 7rem;
446
+ }
447
+ }
448
+
385
449
  .features-section {
386
450
  padding: var(--spacing-16) var(--spacing-6) var(--spacing-20);
387
451
  background: linear-gradient(180deg, var(--background) 0%, oklch(from var(--background) calc(l + 0.02) c h) 100%);
@@ -394,7 +458,7 @@
394
458
  .features-header {
395
459
  text-align: center;
396
460
  max-width: 600px;
397
- margin: 0 auto var(--spacing-12);
461
+ margin: 0 auto var(--spacing-20);
398
462
  }
399
463
 
400
464
  .features-label {
@@ -407,15 +471,15 @@
407
471
  }
408
472
 
409
473
  .features-title {
410
- font-size: var(--text-2xl);
411
- font-weight: var(--font-semibold);
474
+ font-size: clamp(2rem, 4vw, 3rem);
475
+ font-weight: 700;
412
476
  color: var(--foreground);
413
477
  margin: 0 0 var(--spacing-3) 0;
414
478
  }
415
479
 
416
480
  .features-description {
417
481
  color: var(--muted-foreground);
418
- font-size: var(--text-base);
482
+ font-size: var(--text-lg);
419
483
  margin: 0;
420
484
  line-height: 1.6;
421
485
  }
@@ -478,6 +542,7 @@
478
542
  flex-direction: column;
479
543
  gap: var(--spacing-4);
480
544
  padding: var(--spacing-6);
545
+ height: 100%;
481
546
  background: var(--card);
482
547
  border: 1px solid var(--border);
483
548
  border-radius: var(--radius-xl);
@@ -746,6 +811,10 @@ a.feature-card:active {
746
811
  padding: var(--spacing-10) var(--spacing-4) var(--spacing-12);
747
812
  }
748
813
 
814
+ .hero-custom-visual--bottom + .features-section {
815
+ padding-top: var(--spacing-2);
816
+ }
817
+
749
818
  .features-header {
750
819
  margin-bottom: var(--spacing-8);
751
820
  }