hotdocs 0.4.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.
@@ -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 24 24" class="external-link__icon">
33
- <path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path>
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 40 40" class="edit-link__icon">
66
- <path fill="currentColor" d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path>
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
 
@@ -81,6 +83,58 @@ module Hotdocs
81
83
  content_tag(:div, id: id, data: data, style: "visibility: hidden;", &)
82
84
  end
83
85
 
86
+ PATHS_BY_ALERT_TYPE = {
87
+ "danger" => [
88
+ "M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z",
89
+ "M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z"
90
+ ],
91
+ "warning" => [
92
+ "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"
93
+ ],
94
+ "tip" => [
95
+ "M12 18v-5.25m0 0a6.01 6.01 0 0 0 1.5-.189m-1.5.189a6.01 6.01 0 0 1-1.5-.189m3.75 7.478a12.06 12.06 0 0 1-4.5 0m3.75 2.383a14.406 14.406 0 0 1-3 0M14.25 18v-.192c0-.983.658-1.823 1.508-2.316a7.5 7.5 0 1 0-7.517 0c.85.493 1.509 1.333 1.509 2.316V18"
96
+ ],
97
+ "info" => [
98
+ "m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z"
99
+ ]
100
+ }
101
+
102
+ def alert(type, &block)
103
+ paths = PATHS_BY_ALERT_TYPE.fetch(type.to_s)
104
+
105
+ content_tag(:div, class: "alert alert--#{type}") do
106
+ content_tag(:div) do
107
+ concat(
108
+ content_tag(:div, class: "alert__header") do
109
+ concat(
110
+ content_tag(
111
+ :svg,
112
+ class: "alert__icon",
113
+ xmlns: "http://www.w3.org/2000/svg",
114
+ fill: "none",
115
+ viewBox: "0 0 24 24",
116
+ "stroke-width": "1.5",
117
+ stroke: "currentColor"
118
+ ) do
119
+ paths.each do |path|
120
+ concat(content_tag(:path, {}, "stroke-linecap": "round", "stroke-linejoin": "round", d: path))
121
+ end
122
+ end
123
+ )
124
+ concat(content_tag(:span, type.upcase, class: "alert__label"))
125
+ end
126
+ )
127
+ concat(content_tag(:div, class: "alert__content", &block))
128
+ end
129
+ end
130
+ end
131
+
132
+ def external_url?(url)
133
+ !URI.parse(url).host.nil?
134
+ rescue URI::InvalidURIError
135
+ false
136
+ end
137
+
84
138
  private
85
139
 
86
140
  def active_link?(url)
@@ -92,7 +146,7 @@ module Hotdocs
92
146
 
93
147
  new_items = items.map do |item|
94
148
  children, expanded_below = compute_menu_r(item[:children])
95
- active = active_link?(item.fetch(:url))
149
+ active = active_link?(item.fetch(:url, nil))
96
150
  expanded = expanded_below || item[:expanded] || active
97
151
  { **item, expanded: expanded, children: children }
98
152
  end
@@ -106,7 +160,7 @@ module Hotdocs
106
160
  content_tag(:ul, class: "menu__section") do
107
161
  items.each do |item|
108
162
  concat(content_tag(:li) do
109
- locals = { expanded: item.fetch(:expanded), label: item.fetch(:label), url: item.fetch(:url) }
163
+ locals = { expanded: item.fetch(:expanded), label: item.fetch(:label), url: item.fetch(:url, nil) }
110
164
  concat(render partial: "hotdocs/menu_row", locals: locals)
111
165
 
112
166
  concat(menu_r(item.fetch(:children)))
@@ -1,11 +1,30 @@
1
1
  <%# locals: (label:, url:, expanded: false) -%>
2
2
 
3
- <%= 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 %>
4
- <%= active_link_to label, url, class: "menu__link" %>
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" %>
5
7
 
6
- <button type="button" class="menu__toggle" data-action="click->accordion#toggle" data-accordion-target="toggle">
7
- <svg class="menu__toggle-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
8
- <path fill="currentColor" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"></path>
9
- </svg>
10
- </button>
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) %>
20
+
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 %>
29
+ <% end %>
11
30
  <% end %>
@@ -1,56 +1,28 @@
1
1
  <!DOCTYPE html>
2
- <html data-theme="light" lang="<%= I18n.locale %>">
2
+ <html lang="<%= I18n.locale %>">
3
3
  <head>
4
4
  <title><%= content_for(:title) %></title>
5
5
 
6
6
  <%= yield :head %>
7
7
 
8
- <%= stylesheet_link_tag "hotdocs/reset", media: "all", "data-turbo-track": "reload" %>
9
8
  <%= stylesheet_link_tag "hotdocs/application", media: "all", "data-turbo-track": "reload" %>
10
9
  </head>
11
10
 
12
- <body data-controller="search">
13
- <dialog data-search-target="search" class="search">
14
- <div data-search-target="dialog" class="search__dialog">
15
- <div class="search__header">
16
- <input autofocus data-action="input->search#search" type="text" class="search__input"></input>
17
- <button aria-label="Close search dialog" type="button" class="search__dismiss" data-action="click->search#close">
18
- <svg viewBox="0 0 15 15">
19
- <g stroke="currentColor" stroke-width="1.2">
20
- <path d="M.75.75l13.5 13.5M14.25.75L.75 14.25"></path>
21
- </g>
22
- </svg>
23
- </button>
24
- </div>
25
-
26
- <template data-search-target="resultTemplate">
27
- <li class="search__result">
28
- <h1></h1>
29
- <a href="#" class="search__result-excerpt"></a>
30
- </li>
31
- </template>
32
-
33
- <ul data-search-target="results">
34
- <li class="search__result search__result--loading">
35
- Loading index...
36
- </li>
37
- </ul>
38
- </div>
39
-
40
- <script type="application/json" data-search-target="data">
41
- <%= raw(Rails.application.assets.resolver.read("search_data.json")&.force_encoding("UTF-8") || [].to_json) %>
42
- </script>
43
- </dialog>
11
+ <body>
12
+ <% if content_for?(:announcement) %>
13
+ <%= content_for(:announcement) %>
14
+ <% end %>
44
15
 
45
16
  <% if content_for?(:hotdocs_nav) %>
46
17
  <%= content_for(:hotdocs_nav) %>
47
18
 
48
19
  <% else %>
49
- <nav class="nav" data-controller="sidenav" data-sidenav-open-class-value="sidenav--open" data-sidenav-main-menu-class-value="sidenav__sections--main">
20
+ <nav class="reset nav" data-controller="sidenav" data-sidenav-open-class-value="sidenav--open" data-sidenav-main-menu-class-value="sidenav__sections--main">
50
21
  <div class="nav__section">
51
22
  <button class="nav__toggle" type="button" aria-label="Toggle navigation" aria-expanded="false" data-action="click->sidenav#open">
52
- <svg viewBox="0 0 30 30" aria-hidden="true">
53
- <path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path>
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"/>
54
26
  </svg>
55
27
  </button>
56
28
 
@@ -78,13 +50,66 @@
78
50
  <% end %>
79
51
  </div>
80
52
 
81
- <button type="button" data-action="click->search#open:stop" class="search-button" aria-label="Open search dialog">
82
- <svg class="search-button__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
83
- <path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
84
- </svg>
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>
85
106
 
86
- <span class="search-button__label">Type / to search</span>
87
- </button>
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 %>
112
+ </div>
88
113
  </div>
89
114
 
90
115
  <div class="sidenav-backdrop"></div>
@@ -101,10 +126,9 @@
101
126
  <% end %>
102
127
 
103
128
  <button aria-label="Close navigation" class="sidenav__toggle" type="button" data-action="click->sidenav#close">
104
- <svg viewBox="0 0 15 15">
105
- <g stroke="currentColor" stroke-width="1.2">
106
- <path d="M.75.75l13.5 13.5M14.25.75L.75 14.25"></path>
107
- </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"/>
108
132
  </svg>
109
133
  </button>
110
134
  </div>
@@ -135,7 +159,7 @@
135
159
  <% end %>
136
160
 
137
161
  <div class="content">
138
- <aside class="menu">
162
+ <aside class="reset menu">
139
163
  <div class="menu__sections">
140
164
  <%= menu %>
141
165
  </div>
@@ -143,7 +167,7 @@
143
167
 
144
168
  <main data-controller="toc" class="main">
145
169
  <div class="central">
146
- <details name="toc" class="toc">
170
+ <details name="toc" class="reset toc">
147
171
  <summary class="toc__label">Table of contents</summary>
148
172
 
149
173
  <ul class="toc__entries" data-toc-target="toc">
@@ -153,19 +177,23 @@
153
177
  </ul>
154
178
  </details>
155
179
 
156
- <article class="article" data-toc-target="article">
180
+ <div class="article" data-toc-target="article">
157
181
  <%= yield %>
158
- </article>
182
+ </div>
159
183
 
160
- <%= edit_link %>
184
+ <div class="reset">
185
+ <%= edit_link %>
186
+ </div>
161
187
  </div>
162
188
 
163
- <div class="sidetoc">
164
- <ul class="sidetoc__entries" data-toc-target="sidetoc">
165
- <template data-toc-target="sidetocTemplate">
166
- <li><a id class="sidetoc__link" href></a></li>
167
- </template>
168
- </ul>
189
+ <div class="reset sidetoc">
190
+ <div class="sidetoc__section">
191
+ <ul class="sidetoc__entries" data-toc-target="sidetoc">
192
+ <template data-toc-target="sidetocTemplate">
193
+ <li><a id class="sidetoc__link" href></a></li>
194
+ </template>
195
+ </ul>
196
+ </div>
169
197
  </div>
170
198
  </main>
171
199
  </div>
@@ -174,7 +202,7 @@
174
202
  <%= content_for(:hotdocs_footer) %>
175
203
 
176
204
  <% else %>
177
- <footer class="footer">
205
+ <footer class="reset footer">
178
206
  <div class="footer__sections">
179
207
  <% footer_items.each do |footer_item| %>
180
208
  <div class="footer__section">
@@ -195,6 +223,6 @@
195
223
  </footer>
196
224
  <% end %>
197
225
 
198
- <p class="credits">Built with Rails &amp; <a class="credits__link" href="https://hotdocsrails.com">HotDocs<img class="credits__logo" src="<%= asset_path "hotdocs/icon.svg" %>" alt="A humanized and happy hot dog" height="32" width="32" /></a></p>
226
+ <p class="reset credits">Built with Rails &amp; <a class="credits__link" href="https://hotdocsrails.com">HotDocs<img class="credits__logo" src="<%= asset_path "hotdocs/icon.svg" %>" alt="A humanized and happy hot dog" height="32" width="32" /></a></p>
199
227
  </body>
200
228
  </html>
@@ -2,8 +2,6 @@ require "kramdown"
2
2
  require "kramdown-parser-gfm"
3
3
  require "rouge"
4
4
 
5
- require_relative "kramdown_alerts"
6
-
7
5
  class MarkdownHandler
8
6
  def call(template, source)
9
7
  # If the template contains a `fetcher`, do not allow Rails to cache the page.
@@ -27,7 +25,7 @@ class MarkdownHandler
27
25
  .new
28
26
  .call(template, source)
29
27
  .split(";")
30
- .grep(/content_for.*\(.*:/)
28
+ .grep(/@output_buffer.append=\(\scontent_for.*\(.*:/)
31
29
 
32
30
  <<~STRING
33
31
  #{content_fors.join(";")}
@@ -1,3 +1,3 @@
1
1
  module Hotdocs
2
- VERSION = "0.4.0"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -60,11 +60,15 @@ create_file(Pathname(destination_root).join("app/views/layouts/hotdocs.html.erb"
60
60
  <%= content_for(:title, "HotDocs") unless content_for?(:title) %>
61
61
  <meta name="viewport" content="width=device-width,initial-scale=1">
62
62
  <%= stylesheet_link_tag "hotdocs/application" %>
63
- <%= stylesheet_link_tag "hotdocs/base" %>
63
+ <%= stylesheet_link_tag "hotdocs/custom" %>
64
64
  <%= stylesheet_link_tag "hotdocs/rouge" %>
65
65
  <%= javascript_importmap_tags "hotdocs" %>
66
66
  <% end %>
67
67
 
68
+ <%= content_for(:announcement) do %>
69
+ <div class="announcement">This is an announcement at the top of the page</div>
70
+ <% end if false %>
71
+
68
72
  <%= render template: "layouts/hotdocs/application" %>
69
73
  FILE
70
74
 
@@ -110,7 +114,7 @@ create_file(Pathname(destination_root).join("app/helpers/hotdocs_helper.rb"), <<
110
114
  ]
111
115
  end
112
116
 
113
- # { label: "", url: *_path, children: [], expanded: false/true }
117
+ # { label: String, url?: [String, nil], children?: Array, expanded: Boolean }
114
118
  def menu_items
115
119
  [
116
120
  { label: "Welcome", url: hotdocs_path },
@@ -153,19 +157,37 @@ create_file(Pathname(destination_root).join("app/helpers/hotdocs_helper.rb"), <<
153
157
  def fetcher_host
154
158
  "http://127.0.0.1:3000"
155
159
  end
160
+
161
+ def search_provider
162
+ "lunr"
163
+ end
156
164
  end
157
165
  FILE
158
166
 
159
167
  empty_directory "app/assets/stylesheets/hotdocs"
160
168
 
161
- create_file(Pathname(destination_root).join("app/assets/stylesheets/hotdocs/base.css"), <<~FILE)
169
+ create_file(Pathname(destination_root).join("app/assets/stylesheets/hotdocs/custom.css"), <<~FILE)
162
170
  :root {
163
171
  --docs-code-background-color: #eee;
164
172
  --docs-code-border-color: #00000022;
165
173
  --docs-text-color: #1c1e21;
166
174
  }
167
175
 
168
- [data-theme=dark]:root {
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) {
169
191
  --docs-code-background-color: #2b2b2b;
170
192
  --docs-code-border-color: #ffffff22;
171
193
  --docs-text-color: #e3e1de;
@@ -294,5 +316,4 @@ empty_directory "app/assets/builds"
294
316
  keep_file "app/assets/builds"
295
317
  if Pathname(destination_root).join(".gitignore").exist?
296
318
  append_to_file(".gitignore", %(\n/app/assets/builds/*\n!/app/assets/builds/.keep\n))
297
- append_to_file(".gitignore", %(\n/node_modules/\n))
298
319
  end
@@ -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
- desc "Build search data"
12
- task index: :environment do
13
- path = Rails.root.join("app/assets/builds/search_data.json")
14
- # Propshaft caches the `@load_path`s. Rendering data goes through Propshaft
15
- # because of the assets, so the file must exist before rendering.
16
- File.write(path, "")
17
- data = render_search_data.call.to_json
18
- File.write(path, data)
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 render_search_data
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 { render_search_data }
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 render_search_data
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.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/search_controller.js
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
@@ -90,7 +91,6 @@ files:
90
91
  - config/importmap.rb
91
92
  - lib/hotdocs.rb
92
93
  - lib/hotdocs/engine.rb
93
- - lib/hotdocs/kramdown_alerts.rb
94
94
  - lib/hotdocs/markdown.rb
95
95
  - lib/hotdocs/version.rb
96
96
  - lib/install/install.rb