rdoc 6.17.0 → 7.0.3

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +196 -0
  3. data/LEGAL.rdoc +6 -0
  4. data/README.md +20 -3
  5. data/lib/rdoc/code_object/any_method.rb +15 -7
  6. data/lib/rdoc/code_object/class_module.rb +38 -8
  7. data/lib/rdoc/code_object/constant.rb +9 -0
  8. data/lib/rdoc/code_object/method_attr.rb +13 -1
  9. data/lib/rdoc/code_object/top_level.rb +13 -1
  10. data/lib/rdoc/generator/aliki.rb +141 -0
  11. data/lib/rdoc/generator/darkfish.rb +3 -1
  12. data/lib/rdoc/generator/template/aliki/_footer.rhtml +1 -1
  13. data/lib/rdoc/generator/template/aliki/_head.rhtml +4 -4
  14. data/lib/rdoc/generator/template/aliki/_header.rhtml +4 -4
  15. data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +1 -1
  16. data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +3 -3
  17. data/lib/rdoc/generator/template/aliki/class.rhtml +10 -12
  18. data/lib/rdoc/generator/template/aliki/css/rdoc.css +230 -24
  19. data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
  20. data/lib/rdoc/generator/template/aliki/js/aliki.js +43 -21
  21. data/lib/rdoc/generator/template/aliki/js/{search.js → search_controller.js} +15 -6
  22. data/lib/rdoc/generator/template/aliki/js/search_navigation.js +105 -0
  23. data/lib/rdoc/generator/template/aliki/js/search_ranker.js +239 -0
  24. data/lib/rdoc/generator/template/aliki/page.rhtml +1 -1
  25. data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
  26. data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +1 -1
  27. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
  28. data/lib/rdoc/generator/template/darkfish/class.rhtml +9 -11
  29. data/lib/rdoc/markup/blank_line.rb +25 -23
  30. data/lib/rdoc/markup/element.rb +21 -0
  31. data/lib/rdoc/markup/hard_break.rb +30 -27
  32. data/lib/rdoc/markup/heading.rb +96 -79
  33. data/lib/rdoc/markup/raw.rb +52 -55
  34. data/lib/rdoc/markup/table.rb +48 -40
  35. data/lib/rdoc/markup.rb +1 -0
  36. data/lib/rdoc/options.rb +1 -1
  37. data/lib/rdoc/rubygems_hook.rb +3 -3
  38. data/lib/rdoc/version.rb +1 -1
  39. data/rdoc.gemspec +1 -1
  40. metadata +9 -6
  41. data/CONTRIBUTING.rdoc +0 -219
@@ -7,13 +7,13 @@
7
7
  <div class="navbar-search navbar-search-desktop" role="search">
8
8
  <form action="#" method="get" accept-charset="utf-8">
9
9
  <input id="search-field" role="combobox" aria-label="Search"
10
- aria-autocomplete="list" aria-controls="search-results"
10
+ aria-autocomplete="list" aria-controls="search-results-desktop"
11
11
  type="text" name="search" placeholder="Search (/) for a class, method..."
12
12
  spellcheck="false" autocomplete="off"
13
13
  title="Type to search, Up and Down to navigate, Enter to load">
14
- <ul id="search-results" aria-label="Search Results"
14
+ <ul id="search-results-desktop" aria-label="Search Results"
15
15
  aria-busy="false" aria-expanded="false"
16
- aria-atomic="false" class="initially-hidden"></ul>
16
+ aria-atomic="false" class="initially-hidden search-results"></ul>
17
17
  </form>
18
18
  </div>
19
19
 
@@ -47,7 +47,7 @@
47
47
  <div class="search-modal-body">
48
48
  <ul id="search-results-mobile" aria-label="Search Results"
49
49
  aria-busy="false" aria-expanded="false"
50
- aria-atomic="false" class="search-modal-results initially-hidden"></ul>
50
+ aria-atomic="false" class="search-results search-modal-results initially-hidden"></ul>
51
51
  <div class="search-modal-empty">
52
52
  <p>No recent searches</p>
53
53
  </div>
@@ -35,7 +35,7 @@
35
35
  <%= h f.page_name %>
36
36
  </a>
37
37
  </li>
38
- <%- next %>
38
+ <%- next -%>
39
39
  <%- end %>
40
40
 
41
41
  <li>
@@ -2,14 +2,14 @@
2
2
  <form action="#" method="get" accept-charset="utf-8">
3
3
  <div id="search-field-wrapper">
4
4
  <input id="search-field" role="combobox" aria-label="Search"
5
- aria-autocomplete="list" aria-controls="search-results"
5
+ aria-autocomplete="list" aria-controls="search-results-desktop"
6
6
  type="text" name="search" placeholder="Search (/) for a class, method, ..." spellcheck="false"
7
7
  autocomplete="off"
8
8
  title="Type to search, Up and Down to navigate, Enter to load">
9
9
  </div>
10
10
 
11
- <ul id="search-results" aria-label="Search Results"
11
+ <ul id="search-results-desktop" aria-label="Search Results"
12
12
  aria-busy="false" aria-expanded="false"
13
- aria-atomic="false" class="initially-hidden"></ul>
13
+ aria-atomic="false" class="initially-hidden search-results"></ul>
14
14
  </form>
15
15
  </div>
@@ -3,7 +3,7 @@
3
3
  <%= render '_header.rhtml' %>
4
4
  <%= render '_sidebar_toggle.rhtml' %>
5
5
 
6
- <nav id="navigation" role="navigation">
6
+ <nav id="navigation" role="navigation" hidden>
7
7
  <%= render '_sidebar_pages.rhtml' %>
8
8
  <%= render '_sidebar_sections.rhtml' %>
9
9
  <%= render '_sidebar_ancestors.rhtml' %>
@@ -110,10 +110,10 @@
110
110
  </section>
111
111
  <%- end %>
112
112
 
113
- <%- klass.methods_by_type(section).each do |type, visibilities|
114
- next if visibilities.empty?
115
- visibilities.each do |visibility, methods|
116
- next if methods.empty? %>
113
+ <%- klass.methods_by_type(section).each do |type, visibilities| %>
114
+ <%- next if visibilities.empty? %>
115
+ <%- visibilities.each do |visibility, methods| %>
116
+ <%- next if methods.empty? %>
117
117
  <section id="<%= visibility %>-<%= type %>-<%= section.aref %>-method-details" class="method-section anchor-link">
118
118
  <header>
119
119
  <h3 id="<%= visibility %>-<%= type %>-methods"><a href="#<%= visibility %>-<%= type %>-methods"><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</a></h3>
@@ -156,15 +156,13 @@
156
156
  <summary>Source</summary>
157
157
  </details>
158
158
  </div>
159
+ <div class="method-source-code" id="<%= method.html_name %>-source">
160
+ <pre class="<%= method.source_language %>" data-language="<%= method.source_language %>"><%= method.markup_code %></pre>
161
+ </div>
159
162
  <%- end %>
160
163
 
161
164
  <%- unless method.skip_description? then %>
162
165
  <div class="method-description">
163
- <%- if method.token_stream then %>
164
- <div class="method-source-code" id="<%= method.html_name %>-source">
165
- <pre class="<%= method.source_language %>" data-language="<%= method.source_language %>"><%= method.markup_code %></pre>
166
- </div>
167
- <%- end %>
168
166
  <%- if method.mixin_from then %>
169
167
  <div class="mixin-from">
170
168
  <%= method.singleton ? "Extended" : "Included" %> from <a href="<%= klass.aref_to(method.mixin_from.path) %>"><%= method.mixin_from.full_name %></a>
@@ -208,8 +206,8 @@
208
206
 
209
207
  <%- end %>
210
208
  </section>
211
- <%- end
212
- end %>
209
+ <%- end %>
210
+ <%- end %>
213
211
  </section>
214
212
  <%- end %>
215
213
  </main>
@@ -85,6 +85,16 @@
85
85
  --color-th-background: var(--color-neutral-100);
86
86
  --color-td-background: var(--color-neutral-50);
87
87
 
88
+ /* Search Type Badge Colors */
89
+ --color-search-type-class-bg: #e6f0ff;
90
+ --color-search-type-class-text: #0050a0;
91
+ --color-search-type-module-bg: #e6ffe6;
92
+ --color-search-type-module-text: #060;
93
+ --color-search-type-constant-bg: #fff0e6;
94
+ --color-search-type-constant-text: #995200;
95
+ --color-search-type-method-bg: #f0e6ff;
96
+ --color-search-type-method-text: #5200a0;
97
+
88
98
  /* RGBA Colors (theme-agnostic) */
89
99
  --color-overlay: rgb(0 0 0 / 50%);
90
100
  --color-emphasis-bg: rgb(255 111 97 / 10%);
@@ -142,6 +152,7 @@
142
152
 
143
153
  /* Shadows */
144
154
  --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%);
155
+ --shadow-md: 0 2px 8px rgb(0 0 0 / 10%);
145
156
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%);
146
157
  --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 10%), 0 8px 10px -6px rgb(0 0 0 / 10%);
147
158
 
@@ -158,6 +169,13 @@
158
169
  /* Transitions */
159
170
  --transition-fast: 150ms ease-in-out;
160
171
  --transition-base: 200ms ease-in-out;
172
+ --transition-slow: 350ms ease-in-out;
173
+ --ease-out-smooth: cubic-bezier(0.4, 0, 0.2, 1);
174
+
175
+ /* Animation Durations */
176
+ --duration-fast: 250ms;
177
+ --duration-base: 300ms;
178
+ --duration-medium: 350ms;
161
179
 
162
180
  /* Z-Index Scale */
163
181
  --z-fixed: 300;
@@ -202,6 +220,7 @@
202
220
  --color-accent-primary: var(--color-primary-500);
203
221
  --color-accent-hover: var(--color-primary-400);
204
222
  --color-accent-subtle: rgb(235 84 79 / 10%);
223
+ --color-accent-subtle-hover: rgb(235 84 79 / 20%);
205
224
  --color-code-bg: var(--color-neutral-800);
206
225
  --color-code-border: var(--color-neutral-700);
207
226
  --color-nav-bg: var(--color-neutral-900);
@@ -209,8 +228,19 @@
209
228
  --color-th-background: var(--color-background-tertiary);
210
229
  --color-td-background: var(--color-background-secondary);
211
230
 
231
+ /* Search Type Badge Colors - Dark Theme */
232
+ --color-search-type-class-bg: #1e3a5f;
233
+ --color-search-type-class-text: #93c5fd;
234
+ --color-search-type-module-bg: #14532d;
235
+ --color-search-type-module-text: #86efac;
236
+ --color-search-type-constant-bg: #451a03;
237
+ --color-search-type-constant-text: #fcd34d;
238
+ --color-search-type-method-bg: #3b0764;
239
+ --color-search-type-method-text: #d8b4fe;
240
+
212
241
  /* Dark theme shadows (slightly more subtle) */
213
242
  --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 40%), 0 1px 2px -1px rgb(0 0 0 / 40%);
243
+ --shadow-md: 0 2px 8px rgb(0 0 0 / 40%);
214
244
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 40%), 0 4px 6px -4px rgb(0 0 0 / 40%);
215
245
  --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 40%), 0 8px 10px -6px rgb(0 0 0 / 40%);
216
246
 
@@ -291,7 +321,12 @@ pre {
291
321
  border-radius: var(--radius-sm);
292
322
  cursor: pointer;
293
323
  opacity: 0.6;
294
- transition: opacity var(--transition-fast), background var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
324
+ transition:
325
+ opacity var(--transition-fast),
326
+ background var(--transition-fast),
327
+ border-color var(--transition-fast),
328
+ transform var(--transition-fast),
329
+ box-shadow var(--transition-fast);
295
330
  display: flex;
296
331
  align-items: center;
297
332
  justify-content: center;
@@ -305,10 +340,18 @@ pre {
305
340
  opacity: 1;
306
341
  background: var(--color-background-tertiary);
307
342
  border-color: var(--color-border-emphasis);
343
+ transform: translateY(-1px);
344
+ box-shadow: var(--shadow-md);
345
+ }
346
+
347
+ .copy-code-button:focus {
348
+ outline: none;
349
+ box-shadow: 0 0 0 3px var(--color-accent-subtle);
308
350
  }
309
351
 
310
352
  .copy-code-button:active {
311
- transform: scale(0.95);
353
+ transform: scale(0.92);
354
+ box-shadow: none;
312
355
  }
313
356
 
314
357
  .copy-code-button svg {
@@ -320,7 +363,7 @@ pre {
320
363
  stroke-linecap: round;
321
364
  stroke-linejoin: round;
322
365
  color: var(--color-text-secondary);
323
- transition: color var(--transition-fast);
366
+ transition: color var(--transition-fast), transform var(--transition-base);
324
367
  }
325
368
 
326
369
  .copy-code-button:hover svg {
@@ -457,7 +500,11 @@ header.top-navbar .navbar-search form {
457
500
  border-radius: var(--radius-md);
458
501
  color: var(--color-text-primary);
459
502
  cursor: pointer;
460
- transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
503
+ transition:
504
+ background var(--transition-fast),
505
+ border-color var(--transition-fast),
506
+ color var(--transition-fast),
507
+ transform var(--transition-fast);
461
508
  font-size: var(--font-size-lg);
462
509
  line-height: 1;
463
510
  width: 2.5rem;
@@ -468,6 +515,7 @@ header.top-navbar .navbar-search form {
468
515
  background: var(--color-background-secondary);
469
516
  border-color: var(--color-accent-primary);
470
517
  color: var(--color-accent-primary);
518
+ transform: scale(1.05);
471
519
  }
472
520
 
473
521
  .theme-toggle:focus {
@@ -476,13 +524,17 @@ header.top-navbar .navbar-search form {
476
524
  box-shadow: 0 0 0 3px var(--color-accent-subtle);
477
525
  }
478
526
 
527
+ .theme-toggle:active {
528
+ transform: scale(0.95);
529
+ }
530
+
479
531
  .theme-toggle-icon {
480
532
  display: inline-block;
481
- transition: transform var(--transition-base);
533
+ transition: transform var(--duration-base) var(--ease-out-smooth);
482
534
  }
483
535
 
484
536
  .theme-toggle:hover .theme-toggle-icon {
485
- transform: rotate(20deg);
537
+ transform: rotate(15deg) scale(1.1);
486
538
  }
487
539
 
488
540
  /* Mobile navbar */
@@ -537,11 +589,33 @@ nav {
537
589
  background: var(--color-nav-bg);
538
590
  color: var(--color-nav-text);
539
591
  overflow: hidden auto;
592
+ overscroll-behavior: contain;
540
593
  display: flex;
541
594
  flex-direction: column;
542
595
  position: sticky;
543
596
  top: var(--layout-header-height);
544
597
  height: calc(100vh - var(--layout-header-height));
598
+ scrollbar-width: thin;
599
+ scrollbar-color: var(--color-border-default) transparent;
600
+ }
601
+
602
+ /* Custom scrollbar for WebKit browsers */
603
+ nav::-webkit-scrollbar {
604
+ width: 6px;
605
+ }
606
+
607
+ nav::-webkit-scrollbar-track {
608
+ background: transparent;
609
+ }
610
+
611
+ nav::-webkit-scrollbar-thumb {
612
+ background: var(--color-border-default);
613
+ border-radius: var(--radius-sm);
614
+ transition: background var(--transition-fast);
615
+ }
616
+
617
+ nav::-webkit-scrollbar-thumb:hover {
618
+ background: var(--color-border-emphasis);
545
619
  }
546
620
 
547
621
  /* Mobile navigation */
@@ -615,6 +689,17 @@ nav ul li {
615
689
  line-height: var(--line-height-relaxed);
616
690
  }
617
691
 
692
+ nav ul li a {
693
+ transition:
694
+ color var(--transition-fast),
695
+ transform var(--transition-fast),
696
+ padding var(--transition-fast);
697
+ }
698
+
699
+ nav ul li a:hover {
700
+ padding-left: var(--space-1);
701
+ }
702
+
618
703
  nav ul ul {
619
704
  padding-left: var(--space-5);
620
705
  margin-top: var(--space-2);
@@ -632,6 +717,17 @@ nav a {
632
717
  text-decoration: none;
633
718
  }
634
719
 
720
+ /* Truncation for direct nav links (not links inside code tags) */
721
+ nav .nav-list > li > a,
722
+ nav .nav-section > ul > li > a,
723
+ nav .nav-section > dl > dd > a {
724
+ display: block;
725
+ max-width: 100%;
726
+ overflow: hidden;
727
+ text-overflow: ellipsis;
728
+ white-space: nowrap;
729
+ }
730
+
635
731
  nav footer {
636
732
  padding: var(--space-4);
637
733
  border-top: 1px solid var(--color-border-default);
@@ -735,6 +831,11 @@ nav .nav-section-title {
735
831
  font-size: var(--font-size-base);
736
832
  font-weight: var(--font-weight-semibold);
737
833
  color: inherit;
834
+ flex: 1;
835
+ min-width: 0;
836
+ overflow: hidden;
837
+ text-overflow: ellipsis;
838
+ white-space: nowrap;
738
839
  }
739
840
 
740
841
  nav .nav-section-chevron {
@@ -1113,19 +1214,54 @@ main .anchor-link:target {
1113
1214
  main .method-source-code {
1114
1215
  visibility: hidden;
1115
1216
  max-height: 0;
1116
- overflow: auto;
1117
- transition: max-height var(--transition-base), visibility var(--transition-base);
1217
+ overflow: hidden;
1218
+ opacity: 0;
1219
+ transform: translateY(-8px);
1220
+ transition:
1221
+ max-height var(--duration-medium) var(--ease-out-smooth),
1222
+ visibility var(--duration-medium),
1223
+ opacity var(--duration-fast) ease-out,
1224
+ transform var(--duration-fast) ease-out;
1118
1225
  }
1119
1226
 
1120
1227
  main .method-source-code pre {
1121
1228
  border-color: var(--color-accent-hover);
1229
+ border-left: 3px solid var(--color-accent-primary);
1122
1230
  width: 100%;
1123
1231
  box-sizing: border-box;
1232
+ transition: border-color var(--transition-fast);
1233
+ scrollbar-width: thin;
1234
+ scrollbar-color: var(--color-border-default) transparent;
1235
+ }
1236
+
1237
+ main .method-source-code pre::-webkit-scrollbar {
1238
+ width: 6px;
1239
+ height: 6px;
1240
+ }
1241
+
1242
+ main .method-source-code pre::-webkit-scrollbar-track {
1243
+ background: transparent;
1244
+ }
1245
+
1246
+ main .method-source-code pre::-webkit-scrollbar-thumb {
1247
+ background: var(--color-border-default);
1248
+ border-radius: var(--radius-sm);
1249
+ }
1250
+
1251
+ main .method-source-code pre::-webkit-scrollbar-thumb:hover {
1252
+ background: var(--color-border-emphasis);
1253
+ }
1254
+
1255
+ main .method-source-code pre::-webkit-scrollbar-corner {
1256
+ background: transparent;
1124
1257
  }
1125
1258
 
1126
1259
  main .method-source-code.active-menu {
1127
1260
  visibility: visible;
1128
1261
  max-height: 100vh;
1262
+ overflow: auto;
1263
+ opacity: 1;
1264
+ transform: translateY(0);
1129
1265
  }
1130
1266
 
1131
1267
  main .method-description .method-calls-super {
@@ -1165,10 +1301,47 @@ main .method-heading .method-args {
1165
1301
  }
1166
1302
 
1167
1303
  main .method-controls {
1168
- line-height: 20px;
1169
1304
  float: right;
1170
- color: var(--color-accent-hover);
1305
+ }
1306
+
1307
+ main .method-controls summary {
1308
+ display: inline-block;
1309
+ line-height: 20px;
1310
+ color: var(--color-accent-primary);
1171
1311
  cursor: pointer;
1312
+ padding: var(--space-1) var(--space-3);
1313
+ border-radius: var(--radius-sm);
1314
+ font-size: var(--font-size-sm);
1315
+ font-weight: var(--font-weight-medium);
1316
+ background: var(--color-accent-subtle);
1317
+ border: 1px solid transparent;
1318
+ transition:
1319
+ color var(--transition-fast),
1320
+ background var(--transition-fast),
1321
+ border-color var(--transition-fast),
1322
+ transform var(--transition-fast);
1323
+ user-select: none;
1324
+ -webkit-user-select: none;
1325
+ list-style: none;
1326
+ }
1327
+
1328
+ main .method-controls summary::-webkit-details-marker {
1329
+ display: none;
1330
+ }
1331
+
1332
+ main .method-controls summary:hover {
1333
+ background: var(--color-primary-100);
1334
+ border-color: var(--color-primary-300);
1335
+ transform: translateY(-1px);
1336
+ }
1337
+
1338
+ main .method-controls summary:active {
1339
+ transform: scale(0.96);
1340
+ }
1341
+
1342
+ [data-theme="dark"] main .method-controls summary:hover {
1343
+ background: var(--color-accent-subtle-hover);
1344
+ border-color: var(--color-primary-500);
1172
1345
  }
1173
1346
 
1174
1347
  main .method-description,
@@ -1637,55 +1810,88 @@ footer.site-footer .footer-bottom:first-child {
1637
1810
  }
1638
1811
 
1639
1812
  /* Search Results */
1640
- #search-results {
1813
+ .search-results {
1641
1814
  font-family: var(--font-primary);
1642
1815
  font-weight: 300;
1643
1816
  }
1644
1817
 
1645
- #search-results a {
1818
+ .search-results a {
1646
1819
  color: var(--color-text-primary);
1647
1820
  }
1648
1821
 
1649
- #search-results a:hover {
1822
+ .search-results a:hover {
1650
1823
  color: var(--color-accent-primary);
1651
1824
  }
1652
1825
 
1653
- #search-results .search-match {
1826
+ .search-results .search-match {
1654
1827
  font-family: var(--font-heading);
1655
1828
  font-weight: normal;
1656
1829
  }
1657
1830
 
1658
- #search-results .search-selected {
1831
+ .search-results .search-selected {
1659
1832
  background: var(--color-code-bg);
1660
1833
  border-bottom: 1px solid transparent;
1661
1834
  }
1662
1835
 
1663
- #search-results li {
1836
+ .search-results li {
1664
1837
  list-style: none;
1665
1838
  border-bottom: 1px solid var(--color-border-default);
1666
1839
  margin-bottom: 0.5em;
1667
1840
  }
1668
1841
 
1669
- #search-results li:last-child {
1842
+ .search-results li:last-child {
1670
1843
  border-bottom: none;
1671
1844
  margin-bottom: 0;
1672
1845
  }
1673
1846
 
1674
- #search-results li p {
1847
+ .search-results li p {
1675
1848
  padding: 0;
1676
1849
  margin: 0.5em;
1677
1850
  }
1678
1851
 
1679
- #search-results .search-namespace {
1852
+ .search-results .search-namespace {
1680
1853
  font-weight: bold;
1681
1854
  }
1682
1855
 
1683
- #search-results li em {
1856
+ .search-results .search-type {
1857
+ display: inline-block;
1858
+ margin-left: var(--space-2);
1859
+ padding: 0 var(--space-2);
1860
+ font-size: var(--font-size-xs);
1861
+ font-weight: 500;
1862
+ border-radius: var(--radius-sm);
1863
+ vertical-align: middle;
1864
+ background: var(--color-background-tertiary);
1865
+ color: var(--color-text-secondary);
1866
+ }
1867
+
1868
+ .search-results .search-type-class {
1869
+ background: var(--color-search-type-class-bg);
1870
+ color: var(--color-search-type-class-text);
1871
+ }
1872
+
1873
+ .search-results .search-type-module {
1874
+ background: var(--color-search-type-module-bg);
1875
+ color: var(--color-search-type-module-text);
1876
+ }
1877
+
1878
+ .search-results .search-type-constant {
1879
+ background: var(--color-search-type-constant-bg);
1880
+ color: var(--color-search-type-constant-text);
1881
+ }
1882
+
1883
+ .search-results .search-type-instance-method,
1884
+ .search-results .search-type-class-method {
1885
+ background: var(--color-search-type-method-bg);
1886
+ color: var(--color-search-type-method-text);
1887
+ }
1888
+
1889
+ .search-results li em {
1684
1890
  background-color: var(--color-search-highlight-bg);
1685
1891
  font-style: normal;
1686
1892
  }
1687
1893
 
1688
- #search-results pre {
1894
+ .search-results pre {
1689
1895
  margin: 0.5em;
1690
1896
  font-family: var(--font-code);
1691
1897
  }
@@ -1712,7 +1918,7 @@ header.top-navbar #search-field::placeholder {
1712
1918
  }
1713
1919
 
1714
1920
  /* Search results dropdown in navbar */
1715
- header.top-navbar #search-results {
1921
+ header.top-navbar #search-results-desktop {
1716
1922
  position: absolute;
1717
1923
  top: calc(100% + var(--space-2));
1718
1924
  left: 0;
@@ -1728,10 +1934,10 @@ header.top-navbar #search-results {
1728
1934
  padding: 0;
1729
1935
  }
1730
1936
 
1731
- header.top-navbar #search-results.initially-hidden {
1937
+ header.top-navbar #search-results-desktop.initially-hidden {
1732
1938
  display: none;
1733
1939
  }
1734
1940
 
1735
- header.top-navbar #search-results[aria-expanded="false"] {
1941
+ header.top-navbar #search-results-desktop[aria-expanded="false"] {
1736
1942
  display: none;
1737
1943
  }
@@ -3,7 +3,7 @@
3
3
  <%= render '_header.rhtml' %>
4
4
  <%= render '_sidebar_toggle.rhtml' %>
5
5
 
6
- <nav id="navigation" role="navigation">
6
+ <nav id="navigation" role="navigation" hidden>
7
7
  <%= render '_sidebar_pages.rhtml' %>
8
8
  <%= render '_sidebar_classes.rhtml' %>
9
9
  </nav>
@@ -28,7 +28,7 @@ function createSearchInstance(input, result) {
28
28
 
29
29
  result.classList.remove("initially-hidden");
30
30
 
31
- const search = new Search(search_data, input, result);
31
+ const search = new SearchController(search_data, input, result);
32
32
 
33
33
  search.renderItem = function(result) {
34
34
  const li = document.createElement('li');
@@ -40,8 +40,12 @@ function createSearchInstance(input, result) {
40
40
  html += `<span class="params">${result.params}</span>`;
41
41
  html += '</a>';
42
42
 
43
- if (result.namespace)
44
- html += `<p class="search-namespace">${this.hlt(result.namespace)}`;
43
+ // Add type indicator
44
+ if (result.type) {
45
+ const typeLabel = this.formatType(result.type);
46
+ const typeClass = result.type.replace(/_/g, '-');
47
+ html += `<span class="search-type search-type-${this.escapeHTML(typeClass)}">${typeLabel}</span>`;
48
+ }
45
49
 
46
50
  if (result.snippet)
47
51
  html += `<div class="search-snippet">${result.snippet}</div>`;
@@ -51,16 +55,19 @@ function createSearchInstance(input, result) {
51
55
  return li;
52
56
  }
53
57
 
58
+ search.formatType = function(type) {
59
+ const typeLabels = {
60
+ 'class': 'class',
61
+ 'module': 'module',
62
+ 'constant': 'const',
63
+ 'instance_method': 'method',
64
+ 'class_method': 'method'
65
+ };
66
+ return typeLabels[type] || type;
67
+ }
68
+
54
69
  search.select = function(result) {
55
- let href = result.firstChild.firstChild.href;
56
- const query = this.input.value;
57
- if (query) {
58
- const url = new URL(href, window.location.origin);
59
- url.searchParams.set('q', query);
60
- url.searchParams.set('nav', '0');
61
- href = url.toString();
62
- }
63
- window.location.href = href;
70
+ window.location.href = result.firstChild.firstChild.href;
64
71
  }
65
72
 
66
73
  search.scrollIntoView = search.scrollInWindow;
@@ -70,7 +77,7 @@ function createSearchInstance(input, result) {
70
77
 
71
78
  function hookSearch() {
72
79
  const input = document.querySelector('#search-field');
73
- const result = document.querySelector('#search-results');
80
+ const result = document.querySelector('#search-results-desktop');
74
81
 
75
82
  if (!input || !result) return; // Exit if search elements not found
76
83
 
@@ -82,15 +89,27 @@ function hookSearch() {
82
89
  const search = createSearchInstance(input, result);
83
90
  if (!search) return;
84
91
 
92
+ // Hide search results when clicking outside the search area
93
+ document.addEventListener('click', (e) => {
94
+ if (!e.target.closest('.navbar-search-desktop')) {
95
+ search.hide();
96
+ }
97
+ });
98
+
99
+ // Show search results when focusing on input (if there's a query)
100
+ input.addEventListener('focus', () => {
101
+ if (input.value.trim()) {
102
+ search.show();
103
+ }
104
+ });
105
+
85
106
  // Check for ?q= URL parameter and trigger search automatically
86
107
  if (typeof URLSearchParams !== 'undefined') {
87
108
  const urlParams = new URLSearchParams(window.location.search);
88
109
  const queryParam = urlParams.get('q');
89
110
  if (queryParam) {
90
- const navParam = urlParams.get('nav');
91
- const autoSelect = navParam !== '0';
92
111
  input.value = queryParam;
93
- search.search(queryParam, autoSelect);
112
+ search.search(queryParam, false);
94
113
  }
95
114
  }
96
115
  }
@@ -143,9 +162,12 @@ function hookSidebar() {
143
162
  });
144
163
 
145
164
  const isSmallViewport = window.matchMedia("(max-width: 1023px)").matches;
146
- if (isSmallViewport) {
147
- closeNav();
148
165
 
166
+ // The sidebar is hidden by default with the `hidden` attribute
167
+ // On large viewports, we display the sidebar with JavaScript
168
+ // This is better than the opposite approach of hiding it with JavaScript
169
+ // because it avoids flickering the sidebar when the page is loaded, especially on mobile devices
170
+ if (isSmallViewport) {
149
171
  // Close nav when clicking links inside it
150
172
  document.addEventListener('click', (e) => {
151
173
  if (e.target.closest('#navigation a')) {
@@ -161,6 +183,8 @@ function hookSidebar() {
161
183
  closeNav();
162
184
  }
163
185
  });
186
+ } else {
187
+ openNav();
164
188
  }
165
189
  }
166
190
 
@@ -363,9 +387,7 @@ function hookSearchModal() {
363
387
  if (queryParam && isSmallViewport) {
364
388
  openSearchModal();
365
389
  searchInput.value = queryParam;
366
- const navParam = urlParams.get('nav');
367
- const autoSelect = navParam !== '0';
368
- mobileSearch.search(queryParam, autoSelect);
390
+ mobileSearch.search(queryParam, false);
369
391
  }
370
392
  }
371
393
  }