hotdocs 0.1.0 → 0.3.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.
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html data-theme="light">
2
+ <html data-theme="light" lang="<%= I18n.locale %>">
3
3
  <head>
4
4
  <title><%= content_for(:title) %></title>
5
5
 
@@ -9,81 +9,130 @@
9
9
  <%= stylesheet_link_tag "hotdocs/application", media: "all", "data-turbo-track": "reload" %>
10
10
  </head>
11
11
 
12
- <body>
13
- <nav class="nav" data-controller="sidenav" data-sidenav-open-class-value="sidenav--open" data-sidenav-main-menu-class-value="sidenav__sections--main">
14
- <div class="nav__section">
15
- <button class="nav__toggle" type="button" aria-label="Toggle navigation" aria-expanded="false" data-action="click->sidenav#open">
16
- <svg viewBox="0 0 30 30" aria-hidden="true">
17
- <path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path>
18
- </svg>
19
- </button>
20
-
21
- <%= link_to root_path, class: "nav__brand" do %>
22
- <div class="nav__logo-wrapper">
23
- <img class="nav__logo" src="<%= logo.src %>" alt="<%= logo.alt %>" height="32" width="32" />
24
- </div>
25
-
26
- <span class="nav__title">HotDocs</span>
27
- <% end %>
28
-
29
- <div class="nav__links">
30
- <% nav_left_items("nav__link").each do |item| %>
31
- <%= item %>
32
- <% end %>
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>
33
24
  </div>
34
- </div>
35
25
 
36
- <div class="nav__section">
37
- <div class="nav__links">
38
- <% nav_right_items("nav__link").each do |item| %>
39
- <%= item %>
40
- <% end %>
41
- </div>
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>
42
38
  </div>
43
39
 
44
- <div class="sidenav-backdrop"></div>
45
- <div class="sidenav">
46
- <div class="sidenav__header">
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>
44
+
45
+ <% if content_for?(:hotdocs_nav) %>
46
+ <%= content_for(:hotdocs_nav) %>
47
+
48
+ <% else %>
49
+ <nav class="nav" data-controller="sidenav" data-sidenav-open-class-value="sidenav--open" data-sidenav-main-menu-class-value="sidenav__sections--main">
50
+ <div class="nav__section">
51
+ <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>
54
+ </svg>
55
+ </button>
56
+
47
57
  <%= link_to root_path, class: "nav__brand" do %>
48
- <div class="nav__logo-wrapper">
49
- <img class="nav__logo" src="<%= logo.src %>" alt="<%= logo.alt %>" height="32" width="32" />
50
- </div>
58
+ <% unless logo.nil? %>
59
+ <div class="nav__logo-wrapper">
60
+ <img class="nav__logo" src="<%= logo.src %>" alt="<%= logo.alt %>" height="32" width="32" />
61
+ </div>
62
+ <% end %>
51
63
 
52
- <span class="nav__title">HotDocs</span>
64
+ <span class="nav__title"><%= title %></span>
53
65
  <% end %>
54
66
 
55
- <button aria-label="Close navigation" class="sidenav__toggle" type="button" data-action="click->sidenav#close">
56
- <svg viewBox="0 0 15 15">
57
- <g stroke="currentColor" stroke-width="1.2">
58
- <path d="M.75.75l13.5 13.5M14.25.75L.75 14.25"></path>
59
- </g>
67
+ <div class="nav__links">
68
+ <% nav_left_items("nav__link").each do |item| %>
69
+ <%= item %>
70
+ <% end %>
71
+ </div>
72
+ </div>
73
+
74
+ <div class="nav__section">
75
+ <div class="nav__links">
76
+ <% nav_right_items("nav__link").each do |item| %>
77
+ <%= item %>
78
+ <% end %>
79
+ </div>
80
+
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" />
60
84
  </svg>
85
+
86
+ <span class="search-button__label">Type / to search</span>
61
87
  </button>
62
88
  </div>
63
89
 
64
- <div class="sidenav__sections" data-sidenav-target="sections">
65
- <div class="sidenav__section">
66
- <ul class="menu__section">
67
- <% (nav_left_items("menu__link") + nav_right_items("menu__link")).each do |item| %>
68
- <li>
69
- <div class="menu__row">
70
- <%= item %>
71
- </div>
72
- </li>
90
+ <div class="sidenav-backdrop"></div>
91
+ <div class="sidenav">
92
+ <div class="sidenav__header">
93
+ <%= link_to root_path, class: "nav__brand" do %>
94
+ <% unless logo.nil? %>
95
+ <div class="nav__logo-wrapper">
96
+ <img class="nav__logo" src="<%= logo.src %>" alt="<%= logo.alt %>" height="32" width="32" />
97
+ </div>
73
98
  <% end %>
74
- </ul>
99
+
100
+ <span class="nav__title"><%= title %></span>
101
+ <% end %>
102
+
103
+ <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>
108
+ </svg>
109
+ </button>
75
110
  </div>
76
111
 
77
- <div class="sidenav__section">
78
- <div class="menu__section">
79
- <button type="button" class="sidenav__back-button" data-action="click->sidenav#back">← Back to main menu</button>
112
+ <div class="sidenav__sections" data-sidenav-target="sections">
113
+ <div class="sidenav__section">
114
+ <ul class="menu__section">
115
+ <% (nav_left_items("menu__link") + nav_right_items("menu__link")).each do |item| %>
116
+ <li>
117
+ <div class="menu__row">
118
+ <%= item %>
119
+ </div>
120
+ </li>
121
+ <% end %>
122
+ </ul>
80
123
  </div>
81
124
 
82
- <%= menu %>
125
+ <div class="sidenav__section">
126
+ <div class="menu__section">
127
+ <button type="button" class="sidenav__back-button" data-action="click->sidenav#back">← Back to main menu</button>
128
+ </div>
129
+
130
+ <%= menu %>
131
+ </div>
83
132
  </div>
84
133
  </div>
85
- </div>
86
- </nav>
134
+ </nav>
135
+ <% end %>
87
136
 
88
137
  <div class="content">
89
138
  <aside class="menu">
@@ -121,24 +170,31 @@
121
170
  </main>
122
171
  </div>
123
172
 
124
- <footer class="footer">
125
- <div class="footer__sections">
126
- <% footer_items.each do |footer_item| %>
127
- <div class="footer__section">
128
- <p class="footer__heading"><%= footer_item.fetch(:heading) %></p>
173
+ <% if content_for?(:hotdocs_footer) %>
174
+ <%= content_for(:hotdocs_footer) %>
175
+
176
+ <% else %>
177
+ <footer class="footer">
178
+ <div class="footer__sections">
179
+ <% footer_items.each do |footer_item| %>
180
+ <div class="footer__section">
181
+ <p class="footer__heading"><%= footer_item.fetch(:heading) %></p>
182
+
183
+ <ul>
184
+ <% footer_item.fetch(:items).each do |item| %>
185
+ <li><%= item %></li>
186
+ <% end %>
187
+ </ul>
188
+ </div>
189
+ <% end %>
190
+ </div>
129
191
 
130
- <ul>
131
- <% footer_item.fetch(:items).each do |item| %>
132
- <li><%= item %></li>
133
- <% end %>
134
- </ul>
135
- </div>
192
+ <% unless logo.nil? %>
193
+ <img class="footer__logo" src="<%= logo.src %>" alt="<%= logo.alt %>" height="150" width="150" />
136
194
  <% end %>
137
- </div>
138
-
139
- <img class="footer__logo" src="<%= logo.src %>" alt="<%= logo.alt %>" height="150" width="150" />
195
+ </footer>
196
+ <% end %>
140
197
 
141
- <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>
142
- </footer>
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>
143
199
  </body>
144
200
  </html>
data/config/importmap.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  # Pin npm packages by running ./bin/importmap
2
2
 
3
- pin_all_from Hotdocs::Engine.root.join("app/assets/javascript/controllers"), under: "controllers"
3
+ pin_all_from Hotdocs::Engine.root.join("app/assets/javascript/controllers"), to: "controllers", under: "hotdocs/controllers", preload: "hotdocs"
@@ -13,8 +13,7 @@ module Hotdocs
13
13
  end
14
14
 
15
15
  config.before_initialize do
16
- MarkdownHandler.prepare(self)
17
- ActionView::Template.register_template_handler :mderb, MarkdownHandler.new(self)
16
+ ActionView::Template.register_template_handler :mderb, MarkdownHandler.new
18
17
  end
19
18
  end
20
19
  end
@@ -0,0 +1,92 @@
1
+ module Kramdown
2
+ class Element
3
+ def to_h
4
+ {
5
+ children: children.map(&:to_h),
6
+ type:,
7
+ value:
8
+ }
9
+ end
10
+ end
11
+ end
12
+
13
+ module Alert
14
+ PATHS_BY_ALERT_TYPE = {
15
+ "danger" => [
16
+ "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",
17
+ "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"
18
+ ],
19
+ "warning" => [
20
+ "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"
21
+ ],
22
+ "tip" => [
23
+ "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"
24
+ ],
25
+ "info" => [
26
+ "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"
27
+ ]
28
+ }
29
+
30
+ def convert_blockquote(el, indent)
31
+ child = el.children[0]
32
+
33
+ case child.to_h
34
+ in {
35
+ type: :p,
36
+ children: [
37
+ { type: :text, value: /\A\[!(INFO|TIP|WARNING|DANGER)\]\z/ },
38
+ { type: :br },
39
+ *
40
+ ]
41
+ }
42
+ alert_type = $+.downcase
43
+ child.children.slice!(0, 2) # remove :text & :br
44
+
45
+ svg = Kramdown::Element.new(
46
+ :html_element,
47
+ :svg,
48
+ {
49
+ class: "alert__icon",
50
+ xmlns: "http://www.w3.org/2000/svg",
51
+ fill: "none",
52
+ viewBox: "0 0 24 24",
53
+ "stroke-width": "1.5",
54
+ stroke: "currentColor"
55
+ }
56
+ )
57
+
58
+ PATHS_BY_ALERT_TYPE[alert_type].each do |path|
59
+ svg.children << Kramdown::Element.new(:html_element, :path, {
60
+ "stroke-linecap": "round",
61
+ "stroke-linejoin": "round",
62
+ d: path
63
+ })
64
+ end
65
+
66
+ label = Kramdown::Element.new(:html_element, :span, { class: "alert__label" })
67
+ label.children << Kramdown::Element.new(:text, alert_type.upcase)
68
+
69
+ header = Kramdown::Element.new(:html_element, :div, { class: "alert__header" })
70
+ header.children << svg
71
+ header.children << label
72
+
73
+ content = Kramdown::Element.new(:html_element, :div, { class: "alert__content" })
74
+ content.children.push(*el.children)
75
+
76
+ alert = Kramdown::Element.new(:html_element, :div, {})
77
+ alert.children << header
78
+ alert.children << content
79
+
80
+ format_as_block_html(
81
+ "div",
82
+ { class: "alert alert--#{alert_type}" },
83
+ format_as_indented_block_html("div", {}, inner(alert, indent), indent),
84
+ indent
85
+ )
86
+ else
87
+ super
88
+ end
89
+ end
90
+ end
91
+
92
+ Kramdown::Converter::Html.prepend(Alert)
@@ -1,32 +1,28 @@
1
- require "open3"
1
+ require "kramdown"
2
+ require "kramdown-parser-gfm"
3
+ require "rouge"
2
4
 
3
- class MarkdownHandler
4
- def self.prepare(engine)
5
- # Install npm packages
6
- Open3.capture3("deno --allow-read --allow-env --node-modules-dir=auto #{engine.root.join("lib/hotdocs/markdown.mjs")}", stdin_data: "")
7
- rescue
8
- Rails.logger.info("deno not found: Could not install npm packages.")
9
- end
10
-
11
- def initialize(engine)
12
- @engine = engine
13
- end
5
+ require_relative "kramdown_alerts"
14
6
 
7
+ class MarkdownHandler
15
8
  def call(template, source)
16
- compiled = ::HotdocsController.render(inline: source, handler: :erb)
17
- # `capture3` raises if deno is not available
18
- out, err, status = Open3.capture3("deno --allow-read --allow-env --node-modules-dir=auto #{@engine.root.join("lib/hotdocs/markdown.mjs")}", stdin_data: compiled)
19
- Rails.logger.error("Failed to compile markdown: #{err}") unless status.success?
20
-
21
- if !err.empty? && !err.include?("The following packages are deprecated")
22
- # Render the compiled erb (without the md step).
23
- # It won't look great, but better than nothing.
24
- return <<~STRING
25
- @output_buffer.safe_append='#{compiled}'.freeze;
26
- @output_buffer
27
- STRING
9
+ # If the template contains a `fetcher`, do not allow Rails to cache the page.
10
+ if source.match?(%r{<%= fetcher.* do %>})
11
+ ActionView::PathRegistry.all_resolvers.each do |resolver|
12
+ resolver.instance_eval do
13
+ @unbound_templates.delete(template.virtual_path)
14
+ end
15
+ end
28
16
  end
29
17
 
18
+ compiled_template = ::HotdocsController.render(inline: source, handler: :erb)
19
+ out = Kramdown::Document.new(
20
+ compiled_template,
21
+ input: "GFM",
22
+ auto_ids: false,
23
+ syntax_highlighter_opts: { css_class: "highlight" }
24
+ ).to_html
25
+
30
26
  content_fors = ActionView::Template::Handlers::ERB
31
27
  .new
32
28
  .call(template, source)
@@ -35,7 +31,7 @@ class MarkdownHandler
35
31
 
36
32
  <<~STRING
37
33
  #{content_fors.join(";")}
38
- @output_buffer.safe_append='#{out}'.freeze;
34
+ @output_buffer.safe_append='#{out.gsub("'", "\\\\'")}'.freeze;
39
35
  @output_buffer
40
36
  STRING
41
37
  end
@@ -1,3 +1,3 @@
1
1
  module Hotdocs
2
- VERSION = "0.1.0"
2
+ VERSION = "0.3.0"
3
3
  end