hotdocs 0.5.0 → 0.7.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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/app/assets/images/hotdocs/icon.svg +1 -1
- data/app/assets/javascript/controllers/input_cycler_controller.js +19 -0
- data/app/assets/javascript/controllers/{search_controller.js → lunr_controller.js} +1 -1
- data/app/assets/stylesheets/hotdocs/application.css +182 -17
- data/app/helpers/hotdocs/application_helper.rb +6 -4
- data/app/views/hotdocs/_menu_row.html.erb +24 -8
- data/app/views/layouts/hotdocs/application.html.erb +66 -47
- data/lib/hotdocs/version.rb +1 -1
- data/lib/install/install.rb +19 -1
- data/lib/tasks/hotdocs_tasks.rake +24 -19
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c490655dd79fd1f2d45609e7ac0635c33e53a41462b8ff174cef7f73a8d8cec
|
4
|
+
data.tar.gz: 8a0033fe08f447ba4c2868dc01c18dd421e58cb8f5bf5edf778e8d596bd6bae1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6bd387b959fac0bb3e060c1218f3976d997892e6455baac1a55e3cc33ffe660abf8c08032ac3b95e171f43b88a1ac72a30545cb049edaa851840a9c8a64e43f8
|
7
|
+
data.tar.gz: 2eb3ec4d38427ec22b22841843e271feeebb943446070c3c8a3b68fe419f70657113da900350f2fb819bd131197b32682235fd3c80f70f4d187147d06c62dcfe
|
data/README.md
CHANGED
@@ -22,8 +22,8 @@ HotDocs is a set of optimized Rails components & tools for writing docs:
|
|
22
22
|
| Styled components you can customize | ✅ | ✅ | ✅ |
|
23
23
|
| Markdown (with syntax highlight & themes) | ✅ | ✅ | ✅ |
|
24
24
|
| Static export | ✅ | ✅ | ✅ |
|
25
|
-
| Search |
|
26
|
-
| Light / Dark |
|
25
|
+
| Search | ✅ | 🔌 | 🔌 |
|
26
|
+
| Light / Dark | ✅ | 🔌 | ✅ |
|
27
27
|
| Open source | ✅ | ✅ | ✅ |
|
28
28
|
| Free | ✅ | ✅ | ✅ |
|
29
29
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<svg viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
1
|
+
<svg aria-hidden="true" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
2
2
|
<path d="M90 328C243.479 290.664 328.011 197.596 359 91" stroke="#F1B869" stroke-width="120" stroke-linecap="round"/>
|
3
3
|
<path d="M67 376C252.429 326.849 354.56 204.329 392 64" stroke="#E34752" stroke-width="120" stroke-linecap="round"/>
|
4
4
|
<path d="M147 415C300.479 377.664 385.011 284.596 416 178" stroke="#F1B869" stroke-width="160" stroke-linecap="round"/>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
connect() {
|
5
|
+
this.element.addEventListener("click", this._checkNextInput);
|
6
|
+
}
|
7
|
+
|
8
|
+
disconnect() {
|
9
|
+
this.element.removeEventListener("click", this._checkNextInput);
|
10
|
+
}
|
11
|
+
|
12
|
+
_checkNextInput = (event) => {
|
13
|
+
event.preventDefault()
|
14
|
+
const inputs = Array.from(this.element.querySelectorAll('input'))
|
15
|
+
const i = inputs.findIndex(input => input.checked)
|
16
|
+
const j = (i+1) % inputs.length
|
17
|
+
inputs[j].checked = true
|
18
|
+
}
|
19
|
+
}
|
@@ -78,7 +78,7 @@ export default class extends Controller {
|
|
78
78
|
console.warn(
|
79
79
|
[
|
80
80
|
"The search data is not present in the HTML.",
|
81
|
-
"If you are in development, run `bundle exec rails hotdocs:index`.",
|
81
|
+
"If you are in development, run `bundle exec rails hotdocs:lunr:index`.",
|
82
82
|
"If you are in production, assets compilation should have taken care of it.",
|
83
83
|
].join(" ")
|
84
84
|
);
|
@@ -14,9 +14,36 @@
|
|
14
14
|
--link-color: #707070;
|
15
15
|
--nav-height: 3.75rem;
|
16
16
|
--text-color: #1c1e21;
|
17
|
+
color-scheme: light;
|
18
|
+
}
|
19
|
+
|
20
|
+
@media (prefers-color-scheme: dark) {
|
21
|
+
:root {
|
22
|
+
--background-color: #1b1b1d;
|
23
|
+
--code-background-color: #2b2b2b;
|
24
|
+
--code-border-color: #ffffff22;
|
25
|
+
--column-border-color: #535353;
|
26
|
+
--link-active-color: white;
|
27
|
+
--link-color: #909090;
|
28
|
+
--text-color: #e3e1de;
|
29
|
+
color-scheme: dark;
|
30
|
+
}
|
17
31
|
}
|
18
32
|
|
19
|
-
|
33
|
+
:root:has(#scheme-light:checked) {
|
34
|
+
--background-color: white;
|
35
|
+
--code-background-color: #f6f6f6;
|
36
|
+
--code-border-color: #00000022;
|
37
|
+
--column-border-color: #dadada;
|
38
|
+
--content-padding-bottom: 2rem;
|
39
|
+
--link-active-color: black;
|
40
|
+
--link-color: #707070;
|
41
|
+
--nav-height: 3.75rem;
|
42
|
+
--text-color: #1c1e21;
|
43
|
+
color-scheme: light;
|
44
|
+
}
|
45
|
+
|
46
|
+
:root:has(#scheme-dark:checked) {
|
20
47
|
--background-color: #1b1b1d;
|
21
48
|
--code-background-color: #2b2b2b;
|
22
49
|
--code-border-color: #ffffff22;
|
@@ -24,6 +51,7 @@
|
|
24
51
|
--link-active-color: white;
|
25
52
|
--link-color: #909090;
|
26
53
|
--text-color: #e3e1de;
|
54
|
+
color-scheme: dark;
|
27
55
|
}
|
28
56
|
|
29
57
|
html {
|
@@ -54,12 +82,31 @@
|
|
54
82
|
--nav-padding-horizontal: 1.5rem;
|
55
83
|
--nav-padding-vertical: 0.5rem;
|
56
84
|
--nav-shadow: 0 1px 2px 0 #0000001a;
|
85
|
+
--nav-scheme-icon-fill: var(--link-color);
|
86
|
+
--nav-title-color: #1c1e21;
|
87
|
+
--nav-toggle-color: rgb(28, 30, 33);
|
88
|
+
--sidenav-padding-horizontal: 0.75rem;
|
89
|
+
}
|
90
|
+
|
91
|
+
@media (prefers-color-scheme: dark) {
|
92
|
+
:root {
|
93
|
+
--nav-background-color: #242526;
|
94
|
+
--nav-title-color: #e3e1de;
|
95
|
+
--nav-toggle-color: rgb(227, 225, 222);
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
:root:has(#scheme-light:checked) {
|
100
|
+
--nav-background-color: white;
|
101
|
+
--nav-padding-horizontal: 1.5rem;
|
102
|
+
--nav-padding-vertical: 0.5rem;
|
103
|
+
--nav-shadow: 0 1px 2px 0 #0000001a;
|
57
104
|
--nav-title-color: #1c1e21;
|
58
105
|
--nav-toggle-color: rgb(28, 30, 33);
|
59
106
|
--sidenav-padding-horizontal: 0.75rem;
|
60
107
|
}
|
61
108
|
|
62
|
-
|
109
|
+
:root:has(#scheme-dark:checked) {
|
63
110
|
--nav-background-color: #242526;
|
64
111
|
--nav-title-color: #e3e1de;
|
65
112
|
--nav-toggle-color: rgb(227, 225, 222);
|
@@ -81,7 +128,7 @@
|
|
81
128
|
padding: var(--nav-padding-vertical) var(--nav-padding-horizontal);
|
82
129
|
position: sticky;
|
83
130
|
top: 0;
|
84
|
-
z-index:
|
131
|
+
z-index: 100;
|
85
132
|
}
|
86
133
|
|
87
134
|
.nav__section {
|
@@ -144,6 +191,49 @@
|
|
144
191
|
}
|
145
192
|
}
|
146
193
|
|
194
|
+
.scheme {
|
195
|
+
display: flex;
|
196
|
+
height: 1.3rem;
|
197
|
+
position: relative;
|
198
|
+
width: 1.3rem;
|
199
|
+
}
|
200
|
+
|
201
|
+
.scheme__input {
|
202
|
+
-moz-appearance:none;
|
203
|
+
-webkit-appearance:none;
|
204
|
+
appearance:none;
|
205
|
+
background-color: var(--nav-background-color);
|
206
|
+
bottom: 0;
|
207
|
+
left: 0;
|
208
|
+
position: absolute;
|
209
|
+
right: 0;
|
210
|
+
top: 0;
|
211
|
+
}
|
212
|
+
|
213
|
+
.scheme__icon {
|
214
|
+
bottom: 0;
|
215
|
+
cursor: pointer;
|
216
|
+
display: none;
|
217
|
+
fill: var(--nav-scheme-icon-fill);
|
218
|
+
left: 0;
|
219
|
+
position: absolute;
|
220
|
+
right: 0;
|
221
|
+
top: 0;
|
222
|
+
z-index: 10;
|
223
|
+
}
|
224
|
+
|
225
|
+
#scheme-light:checked ~ .scheme__icon--light {
|
226
|
+
display: initial;
|
227
|
+
}
|
228
|
+
|
229
|
+
#scheme-dark:checked ~ .scheme__icon--dark {
|
230
|
+
display: initial;
|
231
|
+
}
|
232
|
+
|
233
|
+
#scheme-auto:checked ~ .scheme__icon--auto {
|
234
|
+
display: initial;
|
235
|
+
}
|
236
|
+
|
147
237
|
.sidenav-backdrop {
|
148
238
|
background-color: rgba(0, 0, 0, .6);
|
149
239
|
inset: 0;
|
@@ -174,6 +264,7 @@
|
|
174
264
|
transition-timing-function: ease-in-out;
|
175
265
|
visibility: hidden;
|
176
266
|
width: 85vw;
|
267
|
+
z-index: 100;
|
177
268
|
}
|
178
269
|
|
179
270
|
.sidenav--open .sidenav {
|
@@ -192,7 +283,6 @@
|
|
192
283
|
padding: var(--nav-padding-vertical) var(--nav-padding-horizontal);
|
193
284
|
position: sticky;
|
194
285
|
top: 0;
|
195
|
-
z-index: 10;
|
196
286
|
}
|
197
287
|
|
198
288
|
.sidenav__toggle {
|
@@ -233,7 +323,23 @@
|
|
233
323
|
--search-text-color: var(--text-color);
|
234
324
|
}
|
235
325
|
|
236
|
-
|
326
|
+
@media (prefers-color-scheme: dark) {
|
327
|
+
:root {
|
328
|
+
--search-background-color: #242526;
|
329
|
+
--search-button-background-color: #1b1b1b;
|
330
|
+
--search-excerpt-background-color: #1b1b1b;
|
331
|
+
--search-excerpt-border-color: #535353;
|
332
|
+
}
|
333
|
+
}
|
334
|
+
|
335
|
+
:root:has(#scheme-light:checked) {
|
336
|
+
--search-background-color: #f5f6f7;
|
337
|
+
--search-button-background-color: #e9e9e9;
|
338
|
+
--search-excerpt-background-color: white;
|
339
|
+
--search-excerpt-border-color: #d7d7d7;
|
340
|
+
}
|
341
|
+
|
342
|
+
:root:has(#scheme-dark:checked) {
|
237
343
|
--search-background-color: #242526;
|
238
344
|
--search-button-background-color: #1b1b1b;
|
239
345
|
--search-excerpt-background-color: #1b1b1b;
|
@@ -248,6 +354,7 @@
|
|
248
354
|
display: flex;
|
249
355
|
gap: 0.5ch;
|
250
356
|
padding: 0.5rem 0.5rem;
|
357
|
+
user-select: none;
|
251
358
|
|
252
359
|
@media (min-width: 40rem) {
|
253
360
|
padding: 0.25rem 0.5rem;
|
@@ -391,7 +498,19 @@
|
|
391
498
|
--menu-link-color: var(--link-color);
|
392
499
|
}
|
393
500
|
|
394
|
-
|
501
|
+
@media (prefers-color-scheme: dark) {
|
502
|
+
:root {
|
503
|
+
--menu-accordion-color: #a0a0a0;
|
504
|
+
--menu-link-hover-background-color: rgba(255, 255, 255, .05);
|
505
|
+
}
|
506
|
+
}
|
507
|
+
|
508
|
+
:root:has(#scheme-light:checked) {
|
509
|
+
--menu-accordion-color: #7f7f7f;
|
510
|
+
--menu-link-hover-background-color: rgba(0, 0, 0, .05);
|
511
|
+
}
|
512
|
+
|
513
|
+
:root:has(#scheme-dark:checked) {
|
395
514
|
--menu-accordion-color: #a0a0a0;
|
396
515
|
--menu-link-hover-background-color: rgba(255, 255, 255, .05);
|
397
516
|
}
|
@@ -433,12 +552,14 @@
|
|
433
552
|
}
|
434
553
|
|
435
554
|
.menu__link {
|
555
|
+
align-items: center;
|
436
556
|
border-radius: 0.25rem;
|
437
557
|
color: var(--menu-link-color);
|
438
|
-
display:
|
558
|
+
display: flex;
|
439
559
|
flex: 1 0 0;
|
560
|
+
height: 2.5rem;
|
440
561
|
overflow: hidden;
|
441
|
-
padding: 0.
|
562
|
+
padding-inline: 0.75rem;
|
442
563
|
text-overflow: ellipsis;
|
443
564
|
white-space: nowrap;
|
444
565
|
|
@@ -484,15 +605,20 @@
|
|
484
605
|
display: flex;
|
485
606
|
}
|
486
607
|
|
608
|
+
.menu__toggle-icon-wrapper {
|
609
|
+
display: flex;
|
610
|
+
justify-content: center;
|
611
|
+
width: 2.5rem;
|
612
|
+
}
|
613
|
+
|
487
614
|
.menu__toggle-icon {
|
488
615
|
color: var(--menu-accordion-color);
|
489
|
-
|
490
|
-
|
491
|
-
width: 2rem;
|
616
|
+
height: 1rem;
|
617
|
+
width: 1rem;
|
492
618
|
}
|
493
619
|
|
494
620
|
.menu__row--expanded .menu__toggle-icon {
|
495
|
-
transform: rotate(
|
621
|
+
transform: rotate(90deg);
|
496
622
|
}
|
497
623
|
|
498
624
|
/* CSS: CONTENT */
|
@@ -541,13 +667,30 @@
|
|
541
667
|
--toc-link-color: #606060;
|
542
668
|
}
|
543
669
|
|
544
|
-
|
670
|
+
@media (prefers-color-scheme: dark) {
|
671
|
+
:root {
|
672
|
+
--toc-background-color: #444444;
|
673
|
+
--toc-divider-color: #909090;
|
674
|
+
--toc-link-active-color: white;
|
675
|
+
--toc-link-color: #c0c0c0;
|
676
|
+
}
|
677
|
+
}
|
678
|
+
|
679
|
+
:root:has(#scheme-light:checked) {
|
680
|
+
--toc-background-color: #e9e9e9;
|
681
|
+
--toc-divider-color: #b0b0b0;
|
682
|
+
--toc-link-active-color: black;
|
683
|
+
--toc-link-color: #606060;
|
684
|
+
}
|
685
|
+
|
686
|
+
:root:has(#scheme-dark:checked) {
|
545
687
|
--toc-background-color: #444444;
|
546
688
|
--toc-divider-color: #909090;
|
547
689
|
--toc-link-active-color: white;
|
548
690
|
--toc-link-color: #c0c0c0;
|
549
691
|
}
|
550
692
|
|
693
|
+
|
551
694
|
.toc {
|
552
695
|
background-color: var(--toc-background-color);
|
553
696
|
border-radius: 5px;
|
@@ -583,7 +726,7 @@
|
|
583
726
|
border-top: 1px solid var(--toc-divider-color);
|
584
727
|
display: flex;
|
585
728
|
flex-direction: column;
|
586
|
-
font-size: 0.
|
729
|
+
font-size: 0.9rem;
|
587
730
|
padding: 0.5rem 0.6rem;
|
588
731
|
gap: 0.4rem;
|
589
732
|
}
|
@@ -652,7 +795,7 @@
|
|
652
795
|
border-left: 1px solid var(--column-border-color);
|
653
796
|
display: flex;
|
654
797
|
flex-direction: column;
|
655
|
-
font-size: 0.
|
798
|
+
font-size: 0.9rem;
|
656
799
|
gap: 0.4rem;
|
657
800
|
padding-inline: 1.5rem;
|
658
801
|
}
|
@@ -726,7 +869,17 @@
|
|
726
869
|
--footer-background-color: #e9e9e9;
|
727
870
|
}
|
728
871
|
|
729
|
-
|
872
|
+
@media (prefers-color-scheme: dark) {
|
873
|
+
:root {
|
874
|
+
--footer-background-color: #444444;
|
875
|
+
}
|
876
|
+
}
|
877
|
+
|
878
|
+
:root:has(#scheme-light:checked) {
|
879
|
+
--footer-background-color: #e9e9e9;
|
880
|
+
}
|
881
|
+
|
882
|
+
:root:has(#scheme-dark:checked) {
|
730
883
|
--footer-background-color: #444444;
|
731
884
|
}
|
732
885
|
|
@@ -872,7 +1025,19 @@
|
|
872
1025
|
--announcement-color: white;
|
873
1026
|
}
|
874
1027
|
|
875
|
-
|
1028
|
+
@media (prefers-color-scheme: dark) {
|
1029
|
+
:root {
|
1030
|
+
--announcement-background-color: white;
|
1031
|
+
--announcement-color: black;
|
1032
|
+
}
|
1033
|
+
}
|
1034
|
+
|
1035
|
+
:root:has(#scheme-light:checked) {
|
1036
|
+
--announcement-background-color: black;
|
1037
|
+
--announcement-color: white;
|
1038
|
+
}
|
1039
|
+
|
1040
|
+
:root:has(#scheme-dark:checked) {
|
876
1041
|
--announcement-background-color: white;
|
877
1042
|
--announcement-color: black;
|
878
1043
|
}
|
@@ -29,8 +29,9 @@ module Hotdocs
|
|
29
29
|
concat(content_tag(:span, name))
|
30
30
|
|
31
31
|
concat(<<~SVG.gsub(/\n/, "").html_safe)
|
32
|
-
<svg aria-hidden="true" viewBox="0 0
|
33
|
-
|
32
|
+
<svg aria-hidden="true" class="external-link__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
|
33
|
+
<!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
|
34
|
+
<path fill="currentColor" d="M384 64C366.3 64 352 78.3 352 96C352 113.7 366.3 128 384 128L466.7 128L265.3 329.4C252.8 341.9 252.8 362.2 265.3 374.7C277.8 387.2 298.1 387.2 310.6 374.7L512 173.3L512 256C512 273.7 526.3 288 544 288C561.7 288 576 273.7 576 256L576 96C576 78.3 561.7 64 544 64L384 64zM144 160C99.8 160 64 195.8 64 240L64 496C64 540.2 99.8 576 144 576L400 576C444.2 576 480 540.2 480 496L480 416C480 398.3 465.7 384 448 384C430.3 384 416 398.3 416 416L416 496C416 504.8 408.8 512 400 512L144 512C135.2 512 128 504.8 128 496L128 240C128 231.2 135.2 224 144 224L224 224C241.7 224 256 209.7 256 192C256 174.3 241.7 160 224 160L144 160z"/>
|
34
35
|
</svg>
|
35
36
|
SVG
|
36
37
|
end
|
@@ -62,8 +63,9 @@ module Hotdocs
|
|
62
63
|
|
63
64
|
link_to(href, html_options) do
|
64
65
|
concat(<<~SVG.html_safe)
|
65
|
-
<svg aria-hidden="true" viewBox="0 0
|
66
|
-
|
66
|
+
<svg aria-hidden="true" class="edit-link__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
|
67
|
+
<!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
|
68
|
+
<path fill="currentColor" d="M416.9 85.2L372 130.1L509.9 268L554.8 223.1C568.4 209.6 576 191.2 576 172C576 152.8 568.4 134.4 554.8 120.9L519.1 85.2C505.6 71.6 487.2 64 468 64C448.8 64 430.4 71.6 416.9 85.2zM338.1 164L122.9 379.1C112.2 389.8 104.4 403.2 100.3 417.8L64.9 545.6C62.6 553.9 64.9 562.9 71.1 569C77.3 575.1 86.2 577.5 94.5 575.2L222.3 539.7C236.9 535.6 250.2 527.9 261 517.1L476 301.9L338.1 164z"/>
|
67
69
|
</svg>
|
68
70
|
SVG
|
69
71
|
|
@@ -1,14 +1,30 @@
|
|
1
1
|
<%# locals: (label:, url:, expanded: false) -%>
|
2
2
|
|
3
|
-
|
4
|
-
<%=
|
5
|
-
|
3
|
+
<% if url.nil? %>
|
4
|
+
<%= content_tag :div, class: "menu__row", data: { "controller": "accordion", "accordion-expanded-class-value": "menu__row--expanded", "accordion-expanded-value": expanded, "accordion-collapsed-aria-label-value": "Expand menu row '#{label}'", "accordion-expanded-aria-label-value": "Collapse menu row '#{label}'" } do %>
|
5
|
+
<%= content_tag :button, type: "button", class: "menu__toggle menu__toggle--full", data: { action: "click->accordion#toggle", "accordion-target": "toggle" } do %>
|
6
|
+
<%= content_tag :span, label, class: "menu__link" %>
|
6
7
|
|
7
|
-
|
8
|
-
|
8
|
+
<div class="menu__toggle-icon-wrapper">
|
9
|
+
<svg aria-hidden="true" class="menu__toggle-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
|
10
|
+
<!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
|
11
|
+
<path fill="currentColor" d="M471.1 297.4C483.6 309.9 483.6 330.2 471.1 342.7L279.1 534.7C266.6 547.2 246.3 547.2 233.8 534.7C221.3 522.2 221.3 501.9 233.8 489.4L403.2 320L233.9 150.6C221.4 138.1 221.4 117.8 233.9 105.3C246.4 92.8 266.7 92.8 279.2 105.3L471.2 297.3z"/>
|
12
|
+
</svg>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
16
|
+
<% else %>
|
17
|
+
<%= content_tag :div, class: "menu__row", data: { "controller": "accordion", "accordion-expanded-class-value": "menu__row--expanded", "accordion-expanded-value": expanded, "accordion-collapsed-aria-label-value": "Expand menu row '#{label}'", "accordion-expanded-aria-label-value": "Collapse menu row '#{label}'" } do %>
|
18
|
+
<%= active_link_to label, url, class: "menu__link" unless external_url?(url) %>
|
19
|
+
<%= external_link_to label, url, class: "menu__link" if external_url?(url) %>
|
9
20
|
|
10
|
-
|
11
|
-
<
|
12
|
-
|
21
|
+
<%= content_tag :button, type: "button", class: "menu__toggle", data: { action: "click->accordion#toggle", "accordion-target": "toggle" } do %>
|
22
|
+
<div class="menu__toggle-icon-wrapper">
|
23
|
+
<svg aria-hidden="true" class="menu__toggle-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
|
24
|
+
<!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
|
25
|
+
<path fill="currentColor" d="M471.1 297.4C483.6 309.9 483.6 330.2 471.1 342.7L279.1 534.7C266.6 547.2 246.3 547.2 233.8 534.7C221.3 522.2 221.3 501.9 233.8 489.4L403.2 320L233.9 150.6C221.4 138.1 221.4 117.8 233.9 105.3C246.4 92.8 266.7 92.8 279.2 105.3L471.2 297.3z"/>
|
26
|
+
</svg>
|
27
|
+
</div>
|
28
|
+
<% end %>
|
13
29
|
<% end %>
|
14
30
|
<% end %>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
|
-
<html
|
2
|
+
<html lang="<%= I18n.locale %>">
|
3
3
|
<head>
|
4
4
|
<title><%= content_for(:title) %></title>
|
5
5
|
|
@@ -8,39 +8,7 @@
|
|
8
8
|
<%= stylesheet_link_tag "hotdocs/application", media: "all", "data-turbo-track": "reload" %>
|
9
9
|
</head>
|
10
10
|
|
11
|
-
<body
|
12
|
-
<dialog data-search-target="search" class="reset search">
|
13
|
-
<div data-search-target="dialog" class="search__dialog">
|
14
|
-
<div class="search__header">
|
15
|
-
<input autofocus data-action="input->search#search" type="text" class="search__input"></input>
|
16
|
-
<button aria-label="Close search dialog" type="button" class="search__dismiss" data-action="click->search#close">
|
17
|
-
<svg viewBox="0 0 15 15">
|
18
|
-
<g stroke="currentColor" stroke-width="1.2">
|
19
|
-
<path d="M.75.75l13.5 13.5M14.25.75L.75 14.25"></path>
|
20
|
-
</g>
|
21
|
-
</svg>
|
22
|
-
</button>
|
23
|
-
</div>
|
24
|
-
|
25
|
-
<template data-search-target="resultTemplate">
|
26
|
-
<li class="search__result">
|
27
|
-
<h1></h1>
|
28
|
-
<a href="#" class="search__result-excerpt"></a>
|
29
|
-
</li>
|
30
|
-
</template>
|
31
|
-
|
32
|
-
<ul data-search-target="results">
|
33
|
-
<li class="search__result search__result--loading">
|
34
|
-
Loading index...
|
35
|
-
</li>
|
36
|
-
</ul>
|
37
|
-
</div>
|
38
|
-
|
39
|
-
<script type="application/json" data-search-target="data">
|
40
|
-
<%= raw(Rails.application.assets.resolver.read("search_data.json")&.force_encoding("UTF-8") || [].to_json) %>
|
41
|
-
</script>
|
42
|
-
</dialog>
|
43
|
-
|
11
|
+
<body>
|
44
12
|
<% if content_for?(:announcement) %>
|
45
13
|
<%= content_for(:announcement) %>
|
46
14
|
<% end %>
|
@@ -52,8 +20,9 @@
|
|
52
20
|
<nav class="reset nav" data-controller="sidenav" data-sidenav-open-class-value="sidenav--open" data-sidenav-main-menu-class-value="sidenav__sections--main">
|
53
21
|
<div class="nav__section">
|
54
22
|
<button class="nav__toggle" type="button" aria-label="Toggle navigation" aria-expanded="false" data-action="click->sidenav#open">
|
55
|
-
<svg viewBox="0 0
|
56
|
-
|
23
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
|
24
|
+
<!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
|
25
|
+
<path fill="currentColor" d="M96 160C96 142.3 110.3 128 128 128L512 128C529.7 128 544 142.3 544 160C544 177.7 529.7 192 512 192L128 192C110.3 192 96 177.7 96 160zM96 320C96 302.3 110.3 288 128 288L512 288C529.7 288 544 302.3 544 320C544 337.7 529.7 352 512 352L128 352C110.3 352 96 337.7 96 320zM544 480C544 497.7 529.7 512 512 512L128 512C110.3 512 96 497.7 96 480C96 462.3 110.3 448 128 448L512 448C529.7 448 544 462.3 544 480z"/>
|
57
26
|
</svg>
|
58
27
|
</button>
|
59
28
|
|
@@ -81,14 +50,65 @@
|
|
81
50
|
<% end %>
|
82
51
|
</div>
|
83
52
|
|
84
|
-
<
|
85
|
-
<
|
86
|
-
|
87
|
-
|
88
|
-
|
53
|
+
<form class="scheme" data-controller="input-cycler" data-turbo-permanent id="scheme">
|
54
|
+
<input class="scheme__input" type="radio" name="scheme" id="scheme-auto" checked />
|
55
|
+
<label class="scheme__icon scheme__icon--auto" role="button" for="scheme-auto" title="System color scheme">
|
56
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M512 320C512 214 426 128 320 128L320 512C426 512 512 426 512 320zM64 320C64 178.6 178.6 64 320 64C461.4 64 576 178.6 576 320C576 461.4 461.4 576 320 576C178.6 576 64 461.4 64 320z"/></svg>
|
57
|
+
</label>
|
58
|
+
|
59
|
+
<input class="scheme__input" type="radio" name="scheme" id="scheme-light" />
|
60
|
+
<label class="scheme__icon scheme__icon--light" for="scheme-light" title="Light color scheme">
|
61
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M210.2 53.9C217.6 50.8 226 51.7 232.7 56.1L320.5 114.3L408.3 56.1C415 51.7 423.4 50.9 430.8 53.9C438.2 56.9 443.4 63.5 445 71.3L465.9 174.5L569.1 195.4C576.9 197 583.5 202.4 586.5 209.7C589.5 217 588.7 225.5 584.3 232.2L526.1 320L584.3 407.8C588.7 414.5 589.5 422.9 586.5 430.3C583.5 437.7 576.9 443.1 569.1 444.6L465.8 465.4L445 568.7C443.4 576.5 438 583.1 430.7 586.1C423.4 589.1 414.9 588.3 408.2 583.9L320.4 525.7L232.6 583.9C225.9 588.3 217.5 589.1 210.1 586.1C202.7 583.1 197.3 576.5 195.8 568.7L175 465.4L71.7 444.5C63.9 442.9 57.3 437.5 54.3 430.2C51.3 422.9 52.1 414.4 56.5 407.7L114.7 320L56.5 232.2C52.1 225.5 51.3 217.1 54.3 209.7C57.3 202.3 63.9 196.9 71.7 195.4L175 174.6L195.9 71.3C197.5 63.5 202.9 56.9 210.2 53.9zM239.6 320C239.6 275.6 275.6 239.6 320 239.6C364.4 239.6 400.4 275.6 400.4 320C400.4 364.4 364.4 400.4 320 400.4C275.6 400.4 239.6 364.4 239.6 320zM448.4 320C448.4 249.1 390.9 191.6 320 191.6C249.1 191.6 191.6 249.1 191.6 320C191.6 390.9 249.1 448.4 320 448.4C390.9 448.4 448.4 390.9 448.4 320z"/></svg>
|
62
|
+
</label>
|
63
|
+
|
64
|
+
<input class="scheme__input" type="radio" name="scheme" id="scheme-dark" />
|
65
|
+
<label class="scheme__icon scheme__icon--dark" for="scheme-dark" title="Dark color scheme">
|
66
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M320 64C178.6 64 64 178.6 64 320C64 461.4 178.6 576 320 576C388.8 576 451.3 548.8 497.3 504.6C504.6 497.6 506.7 486.7 502.6 477.5C498.5 468.3 488.9 462.6 478.8 463.4C473.9 463.8 469 464 464 464C362.4 464 280 381.6 280 280C280 207.9 321.5 145.4 382.1 115.2C391.2 110.7 396.4 100.9 395.2 90.8C394 80.7 386.6 72.5 376.7 70.3C358.4 66.2 339.4 64 320 64z"/></svg>
|
67
|
+
</label>
|
68
|
+
</form>
|
69
|
+
|
70
|
+
<div class="search-box" data-controller="<%= search_provider %>">
|
71
|
+
<% if search_provider == "lunr" %>
|
72
|
+
<button type="button" data-action="click->lunr#open:stop" class="search-box__button" aria-label="Open search dialog">
|
73
|
+
<svg aria-hidden="true" class="search-box__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
|
74
|
+
<!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
|
75
|
+
<path fill="currentColor" d="M480 272C480 317.9 465.1 360.3 440 394.7L566.6 521.4C579.1 533.9 579.1 554.2 566.6 566.7C554.1 579.2 533.8 579.2 521.3 566.7L394.7 440C360.3 465.1 317.9 480 272 480C157.1 480 64 386.9 64 272C64 157.1 157.1 64 272 64C386.9 64 480 157.1 480 272zM272 416C351.5 416 416 351.5 416 272C416 192.5 351.5 128 272 128C192.5 128 128 192.5 128 272C128 351.5 192.5 416 272 416z"/>
|
76
|
+
</svg>
|
77
|
+
|
78
|
+
<span class="search-box__label">Type / to search</span>
|
79
|
+
</button>
|
80
|
+
|
81
|
+
<dialog data-lunr-target="search" class="reset search">
|
82
|
+
<div data-lunr-target="dialog" class="search__dialog">
|
83
|
+
<div class="search__header">
|
84
|
+
<input autofocus data-action="input->lunr#search" type="text" class="search__input"></input>
|
85
|
+
<button aria-label="Close search dialog" type="button" class="search__dismiss" data-action="click->lunr#close">
|
86
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
|
87
|
+
<!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
|
88
|
+
<path fill="currentColor" d="M183.1 137.4C170.6 124.9 150.3 124.9 137.8 137.4C125.3 149.9 125.3 170.2 137.8 182.7L275.2 320L137.9 457.4C125.4 469.9 125.4 490.2 137.9 502.7C150.4 515.2 170.7 515.2 183.2 502.7L320.5 365.3L457.9 502.6C470.4 515.1 490.7 515.1 503.2 502.6C515.7 490.1 515.7 469.8 503.2 457.3L365.8 320L503.1 182.6C515.6 170.1 515.6 149.8 503.1 137.3C490.6 124.8 470.3 124.8 457.8 137.3L320.5 274.7L183.1 137.4z"/>
|
89
|
+
</svg>
|
90
|
+
</button>
|
91
|
+
</div>
|
92
|
+
|
93
|
+
<template data-lunr-target="resultTemplate">
|
94
|
+
<li class="search__result">
|
95
|
+
<h1></h1>
|
96
|
+
<a href="#" class="search__result-excerpt"></a>
|
97
|
+
</li>
|
98
|
+
</template>
|
99
|
+
|
100
|
+
<ul data-lunr-target="results">
|
101
|
+
<li class="search__result search__result--loading">
|
102
|
+
Loading index...
|
103
|
+
</li>
|
104
|
+
</ul>
|
105
|
+
</div>
|
89
106
|
|
90
|
-
|
91
|
-
|
107
|
+
<script type="application/json" data-lunr-target="data">
|
108
|
+
<%= raw(Rails.application.assets.resolver.read("lunr_data.json")&.force_encoding("UTF-8") || [].to_json) %>
|
109
|
+
</script>
|
110
|
+
</dialog>
|
111
|
+
<% end %>
|
92
112
|
</div>
|
93
113
|
</div>
|
94
114
|
|
@@ -106,10 +126,9 @@
|
|
106
126
|
<% end %>
|
107
127
|
|
108
128
|
<button aria-label="Close navigation" class="sidenav__toggle" type="button" data-action="click->sidenav#close">
|
109
|
-
<svg viewBox="0 0
|
110
|
-
|
111
|
-
|
112
|
-
</g>
|
129
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
|
130
|
+
<!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
|
131
|
+
<path fill="currentColor" d="M183.1 137.4C170.6 124.9 150.3 124.9 137.8 137.4C125.3 149.9 125.3 170.2 137.8 182.7L275.2 320L137.9 457.4C125.4 469.9 125.4 490.2 137.9 502.7C150.4 515.2 170.7 515.2 183.2 502.7L320.5 365.3L457.9 502.6C470.4 515.1 490.7 515.1 503.2 502.6C515.7 490.1 515.7 469.8 503.2 457.3L365.8 320L503.1 182.6C515.6 170.1 515.6 149.8 503.1 137.3C490.6 124.8 470.3 124.8 457.8 137.3L320.5 274.7L183.1 137.4z"/>
|
113
132
|
</svg>
|
114
133
|
</button>
|
115
134
|
</div>
|
data/lib/hotdocs/version.rb
CHANGED
data/lib/install/install.rb
CHANGED
@@ -157,6 +157,10 @@ create_file(Pathname(destination_root).join("app/helpers/hotdocs_helper.rb"), <<
|
|
157
157
|
def fetcher_host
|
158
158
|
"http://127.0.0.1:3000"
|
159
159
|
end
|
160
|
+
|
161
|
+
def search_provider
|
162
|
+
"lunr"
|
163
|
+
end
|
160
164
|
end
|
161
165
|
FILE
|
162
166
|
|
@@ -169,7 +173,21 @@ create_file(Pathname(destination_root).join("app/assets/stylesheets/hotdocs/cust
|
|
169
173
|
--docs-text-color: #1c1e21;
|
170
174
|
}
|
171
175
|
|
172
|
-
|
176
|
+
@media (prefers-color-scheme: dark) {
|
177
|
+
:root {
|
178
|
+
--docs-code-background-color: #2b2b2b;
|
179
|
+
--docs-code-border-color: #ffffff22;
|
180
|
+
--docs-text-color: #e3e1de;
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
:root:has(#scheme-light:checked) {
|
185
|
+
--docs-code-background-color: #eee;
|
186
|
+
--docs-code-border-color: #00000022;
|
187
|
+
--docs-text-color: #1c1e21;
|
188
|
+
}
|
189
|
+
|
190
|
+
:root:has(#scheme-dark:checked) {
|
173
191
|
--docs-code-background-color: #2b2b2b;
|
174
192
|
--docs-code-border-color: #ffffff22;
|
175
193
|
--docs-text-color: #e3e1de;
|
@@ -3,40 +3,45 @@ namespace :hotdocs do
|
|
3
3
|
task :install do
|
4
4
|
location = File.expand_path("../install/install.rb", __dir__)
|
5
5
|
system("#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{location}")
|
6
|
-
# Needed for hotdocs:index to find the generated ::HotdocsController
|
6
|
+
# Needed for hotdocs:lunr:index to find the generated ::HotdocsController
|
7
7
|
Rails.application.reloader.reload!
|
8
|
-
Rake::Task["hotdocs:index"].invoke
|
8
|
+
Rake::Task["hotdocs:lunr:index"].invoke
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
namespace :lunr do
|
12
|
+
desc "Prepare lunr data"
|
13
|
+
task index: :environment do
|
14
|
+
helper = Object.new.extend(Hotdocs::ApplicationHelper)
|
15
|
+
next if helper.search_provider != "lunr"
|
16
|
+
|
17
|
+
path = Rails.root.join("app/assets/builds/lunr_data.json")
|
18
|
+
# Propshaft caches the `@load_path`s. Rendering data goes through Propshaft
|
19
|
+
# because of the assets, so the file must exist before rendering.
|
20
|
+
File.write(path, "")
|
21
|
+
data = render_lunr_data.call.to_json
|
22
|
+
File.write(path, data)
|
23
|
+
end
|
19
24
|
end
|
20
25
|
end
|
21
26
|
|
22
27
|
if Rake::Task.task_defined?("assets:precompile")
|
23
|
-
Rake::Task["assets:precompile"].enhance([ "hotdocs:index" ])
|
28
|
+
Rake::Task["assets:precompile"].enhance([ "hotdocs:lunr:index" ])
|
24
29
|
end
|
25
30
|
|
26
31
|
if Rake::Task.task_defined?("test:prepare")
|
27
|
-
Rake::Task["test:prepare"].enhance([ "hotdocs:index" ])
|
32
|
+
Rake::Task["test:prepare"].enhance([ "hotdocs:lunr:index" ])
|
28
33
|
elsif Rake::Task.task_defined?("spec:prepare")
|
29
|
-
Rake::Task["spec:prepare"].enhance([ "hotdocs:index" ])
|
34
|
+
Rake::Task["spec:prepare"].enhance([ "hotdocs:lunr:index" ])
|
30
35
|
elsif Rake::Task.task_defined?("db:test:prepare")
|
31
|
-
Rake::Task["db:test:prepare"].enhance([ "hotdocs:index" ])
|
36
|
+
Rake::Task["db:test:prepare"].enhance([ "hotdocs:lunr:index" ])
|
32
37
|
end
|
33
38
|
|
34
|
-
def
|
39
|
+
def render_lunr_data
|
35
40
|
renderer = Class.new(::HotdocsController) do
|
36
41
|
include Hotdocs::ApplicationHelper
|
37
42
|
|
38
43
|
def call
|
39
|
-
with_no_view_annotations {
|
44
|
+
with_no_view_annotations { render_lunr_data }
|
40
45
|
end
|
41
46
|
|
42
47
|
private
|
@@ -49,7 +54,7 @@ def render_search_data
|
|
49
54
|
Rails.application.config.action_view.annotate_rendered_view_with_filename = annotate
|
50
55
|
end
|
51
56
|
|
52
|
-
def
|
57
|
+
def render_lunr_data
|
53
58
|
pages = pages_from(menu_items)
|
54
59
|
$stderr.puts "Indexing #{pages.size} pages:"
|
55
60
|
render_pages(pages).tap { $stderr.puts }
|
@@ -66,12 +71,12 @@ def render_search_data
|
|
66
71
|
|
67
72
|
def pages_from(menu_items, parent = "Docs")
|
68
73
|
menu_items
|
69
|
-
.filter { _1.fetch(:url).start_with?("/") }
|
70
74
|
.flat_map do |item|
|
71
|
-
current = { title: item.fetch(:label), parent: parent, url: item.fetch(:url) }
|
75
|
+
current = { title: item.fetch(:label), parent: parent, url: item.fetch(:url, "") }
|
72
76
|
children = pages_from(item.fetch(:children, []), item.fetch(:label))
|
73
77
|
[ current ] + children
|
74
78
|
end
|
79
|
+
.filter { _1.fetch(:url).start_with?("/") }
|
75
80
|
end
|
76
81
|
|
77
82
|
def render_path(path)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hotdocs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 3v0k4
|
@@ -79,7 +79,8 @@ files:
|
|
79
79
|
- app/assets/images/hotdocs/icon.svg
|
80
80
|
- app/assets/javascript/controllers/accordion_controller.js
|
81
81
|
- app/assets/javascript/controllers/fetcher_controller.js
|
82
|
-
- app/assets/javascript/controllers/
|
82
|
+
- app/assets/javascript/controllers/input_cycler_controller.js
|
83
|
+
- app/assets/javascript/controllers/lunr_controller.js
|
83
84
|
- app/assets/javascript/controllers/sidenav_controller.js
|
84
85
|
- app/assets/javascript/controllers/toc_controller.js
|
85
86
|
- app/assets/stylesheets/hotdocs/application.css
|