markdowndocs 0.9.0 → 0.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 764b5150885d6a306eae6d49fbabd8dedee96dffa9bc55a6f290da57e3b53123
4
- data.tar.gz: 2a75805e06c5caa6fcdbf8e4860836bcf886fc5453b4d394761f8f45ae8ba114
3
+ metadata.gz: 4066fc2cf3c03c9f743aaaab41c62611b5206ef9d0dad6cdead66c02f39eba29
4
+ data.tar.gz: 9594a84833fca33b4ec4d4a6c81efd1cc21d28e57fddca30f1f4765073ced9bb
5
5
  SHA512:
6
- metadata.gz: 8502ba23be6b2ccafa8abc6f0388fddfaf1eae79da276b2ec676087195f04ddc000c576b636c5f81473c10fe30f2786faa9fa7b901419a3f8689226d6440a86e
7
- data.tar.gz: 0d71e8284d7a5ed9efcdd8841e0a7e760bb26906e4ac61fb27a1ec32e259357c920e6b86ff66bc16e7d3fdda632c2ed5c12b216ff2b71c1f025f3f1ab73aab99
6
+ metadata.gz: 82e59acd421e1b32d0739167035ec770049ac0d27e1e5f00e7f3a9df5a01df00a7419be05443f9ae1ac45110eba1ad23fc0ccc73daf5c56388b2d1d867676d2e
7
+ data.tar.gz: 96b3a5cefdde9a74e349111f33b7f33106e1587d3e1cbeef911a2cdafb0588d3ba43b0dd7cdb591c88256a4d151ecc44e076a0c87d009121cf200b62ee1f21da
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.4.5
data/CHANGELOG.md CHANGED
@@ -5,6 +5,55 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.11.0] - 2026-07-13
9
+
10
+ ### Accessibility
11
+
12
+ - **Keyboard-scrollable tables (WCAG 2.1.1).** A wide GFM table overflows and
13
+ becomes horizontally scrollable via the host's typography CSS. The renderer
14
+ now marks every `<table>` with `tabindex="0"` so keyboard-only users can
15
+ scroll it with the arrow keys (axe `scrollable-region-focusable`). The
16
+ table's implicit `role="table"` is preserved — no `role="region"` is added,
17
+ which would strip row/column semantics — and an un-captioned table gets a
18
+ minimal `aria-label="Table"` so the focus stop is announced. `tabindex` is
19
+ now in the sanitizer's base attribute allow-list.
20
+ - **44px chrome target sizes (WCAG 2.5.5 AAA).** Sidebar table-of-contents
21
+ links, related-documentation links, breadcrumb links, and the audience
22
+ mode-switcher buttons now meet the 44×44 minimum target size (they measured
23
+ ~20–28px). Purely additive utility classes; no visual change beyond the
24
+ taller hit area.
25
+
26
+ ## [0.10.0] - 2026-06-24
27
+
28
+ ### Added
29
+
30
+ - **Persistent audience switcher.** The viewing-mode switcher now renders in a
31
+ toolbar at the top of both the docs index and every doc page (new
32
+ `markdowndocs/docs/_docs_toolbar` partial), instead of only the show-page
33
+ sidebar — the audience choice is always visible and rendered once per page.
34
+ `DocsController#index` and `#show` both expose `@available_modes` from
35
+ `config.modes`.
36
+ - **Screen-reader mode announcement.** Switching audience sets `flash[:notice]`
37
+ (`markdowndocs.mode_announcement`), surfaced in a `role="status"
38
+ aria-live="polite"` region in the engine layout so the Turbo-replace mode
39
+ change isn't silent for assistive tech. Hosts may render the flash their own way.
40
+
41
+ ### Changed
42
+
43
+ - **No-counterpart audience switch goes to the target index.** Switching to a
44
+ mode where the current doc has no counterpart (and no shared-root fallback)
45
+ now redirects to that audience's index — with a distinct flash
46
+ (`markdowndocs.no_counterpart_announcement`) — instead of stranding the reader
47
+ on a doc outside the audience they chose. Topic-preserving (scoped counterpart)
48
+ and shared-root docs are unchanged.
49
+
50
+ ### Fixed
51
+
52
+ - **Mode switcher ARIA: toggle-button group, not a radiogroup.** Each mode is a
53
+ submit button using `aria-pressed` (was `role="radio"` / `aria-checked`, which
54
+ implied unimplemented arrow-key navigation). Focus returns to the chosen button
55
+ after the Turbo replace.
56
+
8
57
  ## [0.9.0] - 2026-06-21
9
58
 
10
59
  ### Added
@@ -16,11 +16,45 @@ export default class extends Controller {
16
16
  }
17
17
 
18
18
  static STORAGE_KEY = "markdowndocs_mode"
19
+ static FOCUS_KEY = "markdowndocs_focus_mode"
19
20
 
20
21
  connect() {
21
22
  if (!this.isAuthenticated()) {
22
23
  this.restoreGuestMode()
23
24
  }
25
+ this.restoreFocusAfterToggle()
26
+ }
27
+
28
+ rememberFocus(event) {
29
+ // Save the mode the user just pressed so we can restore focus to the
30
+ // matching button after Turbo replaces the page (a11y: keep focus on
31
+ // the control the user actuated, not on the article wrapper).
32
+ try {
33
+ const mode = event.currentTarget.dataset.mode
34
+ if (mode) {
35
+ sessionStorage.setItem(this.constructor.FOCUS_KEY, mode)
36
+ }
37
+ } catch (e) {
38
+ // sessionStorage unavailable — accept the focus loss gracefully.
39
+ }
40
+ }
41
+
42
+ restoreFocusAfterToggle() {
43
+ let pendingMode
44
+ try {
45
+ pendingMode = sessionStorage.getItem(this.constructor.FOCUS_KEY)
46
+ if (pendingMode) sessionStorage.removeItem(this.constructor.FOCUS_KEY)
47
+ } catch (e) {
48
+ return
49
+ }
50
+ if (!pendingMode) return
51
+
52
+ const button = this.element.querySelector(`button[data-mode="${pendingMode}"]`)
53
+ if (button) {
54
+ // Defer past the Turbo render + autofocus on the article wrapper so
55
+ // we steal focus from it; otherwise autofocus would win the race.
56
+ window.requestAnimationFrame(() => button.focus())
57
+ }
24
58
  }
25
59
 
26
60
  isAuthenticated() {
@@ -14,6 +14,7 @@ module Markdowndocs
14
14
  # surviving docs are dropped (see Documentation.grouped_by_category).
15
15
  @docs_by_category = Documentation.grouped_by_category(mode: @docs_mode)
16
16
  @search_enabled = Markdowndocs.config.search_enabled
17
+ @available_modes = Markdowndocs.config.modes
17
18
  end
18
19
 
19
20
  def search_index
@@ -64,7 +65,7 @@ module Markdowndocs
64
65
  )
65
66
  @rendered_content = helpers.add_heading_anchors(rendered_html)
66
67
  @related_docs = Documentation.by_category(@doc.category).reject { |d| d.path_slug == @doc.path_slug }
67
- @available_modes = @doc.available_modes
68
+ @available_modes = Markdowndocs.config.modes
68
69
  @toc_items = helpers.generate_table_of_contents(@rendered_content)
69
70
  end
70
71
 
@@ -25,7 +25,25 @@ module Markdowndocs
25
25
  httponly: true
26
26
  }
27
27
 
28
- redirect_to(smart_nav_target(mode, params[:current_path]), status: :see_other)
28
+ current_path = params[:current_path]
29
+ target = smart_nav_target(mode, current_path)
30
+ mode_name = I18n.t("markdowndocs.modes.#{mode}", default: mode.titleize)
31
+
32
+ flash[:notice] = if redirected_to_index_from_doc?(target, current_path)
33
+ I18n.t(
34
+ "markdowndocs.no_counterpart_announcement",
35
+ mode: mode_name,
36
+ default: "No %{mode} version of this page — showing the %{mode} documentation."
37
+ )
38
+ else
39
+ I18n.t(
40
+ "markdowndocs.mode_announcement",
41
+ mode: mode_name,
42
+ default: "Now viewing %{mode}."
43
+ )
44
+ end
45
+
46
+ redirect_to(target, status: :see_other)
29
47
  end
30
48
 
31
49
  private
@@ -50,15 +68,26 @@ module Markdowndocs
50
68
  # rejection (and any other reachability rules) match what the show
51
69
  # action would actually serve. Bypassing this — e.g. with raw
52
70
  # File.exist? — can redirect the user into a 404.
53
- if scoped_sibling_reachable?(slug, target_mode) && current_path != scoped_url
71
+ if scoped_sibling_reachable?(slug, target_mode)
54
72
  scoped_url
55
- elsif root_sibling_reachable?(slug) && current_path != root_url
73
+ elsif root_sibling_reachable?(slug)
56
74
  root_url
57
75
  else
58
- current_path
76
+ # No counterpart in the target mode and no shared root fallback: send the
77
+ # reader to that audience's index rather than stranding them on a doc
78
+ # outside the audience they just chose.
79
+ index_path
59
80
  end
60
81
  end
61
82
 
83
+ # True when the switch had to fall back to the docs index because the current
84
+ # doc has no counterpart in the target mode (selects the flash copy below).
85
+ def redirected_to_index_from_doc?(target, current_path)
86
+ current_path.present? &&
87
+ target == markdowndocs.root_path.chomp("/") &&
88
+ extract_slug_from_path(current_path).present?
89
+ end
90
+
62
91
  def scoped_sibling_reachable?(slug, target_mode)
63
92
  docs_path = Markdowndocs.config.resolved_docs_path
64
93
  scoped_file = docs_path.join(target_mode, "#{slug}.md")
@@ -48,7 +48,7 @@ module Markdowndocs
48
48
  options = markdown_render_options
49
49
  doc = Commonmarker.parse(markdown, options: options)
50
50
  html = doc.to_html(options: options)
51
- html = apply_syntax_highlighting(html)
51
+ html = post_process_html(html)
52
52
  sanitize_html(html)
53
53
  rescue => e
54
54
  # Bare rescue is intentional: third-party errors from commonmarker,
@@ -66,7 +66,7 @@ module Markdowndocs
66
66
  %(<pre class="markdowndocs-render-error">#{escaped}</pre>)
67
67
  end
68
68
 
69
- def apply_syntax_highlighting(html)
69
+ def post_process_html(html)
70
70
  # HTML5 parsing preserves case-sensitive SVG/MathML foreign-content
71
71
  # attributes (e.g. viewBox) that Nokogiri::HTML would lowercase.
72
72
  doc = Nokogiri::HTML5.fragment(html)
@@ -84,9 +84,37 @@ module Markdowndocs
84
84
  end
85
85
  end
86
86
 
87
+ mark_tables_keyboard_accessible(doc)
88
+
87
89
  doc.to_html
88
90
  end
89
91
 
92
+ # A wide GFM table overflows its column and becomes horizontally
93
+ # scrollable — via the host's typography/prose CSS, which the engine
94
+ # does not control and cannot inspect at render time. A scrollable
95
+ # region that isn't keyboard-focusable strands keyboard-only users
96
+ # (WCAG 2.1.1; axe `scrollable-region-focusable`).
97
+ #
98
+ # `tabindex="0"` directly on the <table> makes it focusable so a
99
+ # keyboard user can scroll it with the arrow keys, whether the host CSS
100
+ # scrolls the table itself or a wrapper. We deliberately do NOT add
101
+ # `role="region"`: on a <table> that would override the implicit
102
+ # `role="table"` and strip row/column semantics from screen readers.
103
+ # A <caption> already names the table for AT; when absent we add a
104
+ # minimal aria-label so the focus stop is announced. The focus ring is
105
+ # the user-agent default (no engine CSS suppresses it).
106
+ #
107
+ # Trade-off: every table becomes a tab stop, not only the ones that
108
+ # actually overflow — scroll state is unknowable without a browser, and
109
+ # a static (JS-free) engine fix is worth that small amount of extra tab
110
+ # travel.
111
+ def mark_tables_keyboard_accessible(doc)
112
+ doc.css("table").each do |table|
113
+ table["tabindex"] = "0"
114
+ table["aria-label"] = "Table" unless table.at_css("caption") || table["aria-label"]
115
+ end
116
+ end
117
+
90
118
  def lexer_exists?(language)
91
119
  Rouge::Lexer.find(language).present?
92
120
  rescue
@@ -131,6 +159,7 @@ module Markdowndocs
131
159
  href title src alt align class lang
132
160
  role aria-label aria-labelledby aria-describedby aria-hidden
133
161
  open
162
+ tabindex
134
163
  ].freeze
135
164
 
136
165
  # Curated structural SVG subset. Deliberately excludes script,
@@ -159,7 +188,7 @@ module Markdowndocs
159
188
  transform opacity text-anchor dominant-baseline
160
189
  font-size font-family font-weight
161
190
  marker-start marker-end markerWidth markerHeight refX refY orient
162
- id xmlns focusable tabindex
191
+ id xmlns focusable
163
192
  ].freeze
164
193
 
165
194
  def sanitize_html(html)
@@ -11,6 +11,9 @@
11
11
  </head>
12
12
 
13
13
  <body class="min-h-screen flex flex-col bg-gray-50">
14
+ <% if flash[:notice].present? %>
15
+ <div role="status" aria-live="polite" class="sr-only"><%= flash[:notice] %></div>
16
+ <% end %>
14
17
  <%= yield :docs_header %>
15
18
 
16
19
  <main id="main-content" role="main" class="flex-1">
@@ -19,7 +19,8 @@
19
19
  <% if item[:current] %>
20
20
  <span class="font-medium text-gray-900 dark:text-slate-100" aria-current="page"><%= item[:name] %></span>
21
21
  <% elsif item[:path] %>
22
- <%= link_to item[:name], item[:path], class: "hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors" %>
22
+ <%# inline-flex min-h-11 (44px) meets WCAG 2.5.5 AAA target size. %>
23
+ <%= link_to item[:name], item[:path], class: "hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors inline-flex min-h-11 items-center" %>
23
24
  <% else %>
24
25
  <span class="text-gray-700 dark:text-slate-300"><%= item[:name] %></span>
25
26
  <% end %>
@@ -0,0 +1,10 @@
1
+ <%# locals: (current_mode:, available_modes:) %>
2
+ <%# Persistent docs toolbar: the audience switcher, shown at the top of both
3
+ the index and every doc page. Renders nothing when only one mode exists. %>
4
+ <% if available_modes.length > 1 %>
5
+ <div class="flex justify-end mb-6">
6
+ <%= render "markdowndocs/docs/mode_switcher",
7
+ current_mode: current_mode,
8
+ available_modes: available_modes %>
9
+ </div>
10
+ <% end %>
@@ -1,80 +1,31 @@
1
1
  <%# locals: (current_mode:, available_modes:) %>
2
- <%# No `id=` on the root: show.html.erb renders _navigation twice (mobile +
3
- desktop sidebars), which embeds this partial twice a hardcoded id
4
- would produce duplicate ids in the DOM (WCAG 4.1.1 violation, see
5
- issue #20). Stimulus already scopes itself via data-controller, which
6
- can appear N times without colliding. Tests / selectors should target
7
- [data-controller="docs-mode"] rather than #docs-mode-switcher. %>
2
+ <%# Horizontal audience toggle for the docs toolbar (rendered once per page).
3
+ Toggle-button group, NOT a radiogroup: each option is its own form +
4
+ submit button, so aria-pressed describes state. No element id tests
5
+ target [data-controller="docs-mode"]. %>
8
6
  <div
9
- class="
10
- bg-white
11
- dark:bg-slate-800
12
- rounded-lg
13
- border
14
- border-slate-200
15
- dark:border-slate-700
16
- p-4
17
- "
7
+ class="flex items-center gap-2"
18
8
  data-controller="docs-mode"
19
9
  data-docs-mode-current-value="<%= current_mode %>"
20
10
  >
21
- <h3 class="
22
- text-sm
23
- font-medium
24
- text-slate-700
25
- dark:text-slate-300
26
- mb-3
27
- ">
11
+ <span class="text-sm font-medium text-slate-700 dark:text-slate-300">
28
12
  <%= t("markdowndocs.viewing_mode") %>
29
- </h3>
30
-
31
- <div
32
- class="space-y-2"
33
- role="radiogroup"
34
- aria-label="<%= t('markdowndocs.select_viewing_mode') %>"
35
- >
13
+ </span>
14
+ <div class="inline-flex gap-1" role="group" aria-label="<%= t('markdowndocs.select_viewing_mode') %>">
36
15
  <% available_modes.each do |mode| %>
37
- <%= form_with(
38
- url: markdowndocs.preference_path,
39
- method: :patch,
40
- data: {
41
- turbo_action: "replace"
42
- }
43
- ) do |f| %>
16
+ <%= form_with(url: markdowndocs.preference_path, method: :patch, data: {turbo_action: "replace"}) do |f| %>
44
17
  <%= f.hidden_field :mode, value: mode, id: nil %>
45
18
  <%= f.hidden_field :current_path, value: request.fullpath, id: nil %>
46
19
  <button
47
20
  type="submit"
48
- role="radio"
49
- aria-checked="<%= current_mode == mode %>"
50
- class="
51
- w-full
52
- text-left
53
- p-3
54
- rounded-lg
55
- border-2
56
- transition-all
57
- duration-150
58
- <%= (current_mode == mode) ? 'border-cyan-500 bg-cyan-50 dark:bg-cyan-900/40 dark:border-cyan-400' : 'border-slate-200 hover:border-slate-300 hover:bg-slate-50 dark:border-slate-700 dark:hover:border-slate-500 dark:hover:bg-slate-700' %>
59
- "
21
+ aria-pressed="<%= current_mode == mode %>"
22
+ data-mode="<%= mode %>"
23
+ data-action="click->docs-mode#rememberFocus"
24
+ <%# inline-flex min-h-11 (44px) meets WCAG 2.5.5 AAA target size — the
25
+ toggle buttons measured ~28px tall. %>
26
+ class="inline-flex min-h-11 items-center justify-center px-3 py-1.5 text-sm font-medium rounded-md border transition-colors <%= (current_mode == mode) ? 'border-cyan-500 bg-cyan-50 text-cyan-900 dark:bg-cyan-900/40 dark:border-cyan-400 dark:text-cyan-100' : 'border-slate-200 text-slate-700 hover:bg-slate-50 dark:border-slate-700 dark:text-slate-300 dark:hover:bg-slate-700' %>"
60
27
  >
61
- <span class="
62
- block
63
- font-medium
64
- <%= (current_mode == mode) ? 'text-cyan-900 dark:text-cyan-100' : 'text-slate-900 dark:text-slate-100' %>
65
- ">
66
- <%= t("markdowndocs.modes.#{mode}", default: mode.titleize) %>
67
- </span>
68
- <% description = t("markdowndocs.modes.#{mode}_description", default: "") %>
69
- <% if description.present? %>
70
- <p class="
71
- text-xs
72
- mt-1
73
- <%= (current_mode == mode) ? 'text-cyan-900 dark:text-cyan-100' : 'text-slate-700 dark:text-slate-300' %>
74
- ">
75
- <%= description %>
76
- </p>
77
- <% end %>
28
+ <%= t("markdowndocs.modes.#{mode}", default: mode.titleize) %>
78
29
  </button>
79
30
  <% end %>
80
31
  <% end %>
@@ -1,11 +1,5 @@
1
- <%# locals: (rendered_content:, related_docs:, current_mode:, available_modes:, toc_items:) %>
1
+ <%# locals: (rendered_content:, related_docs:, toc_items:) %>
2
2
  <aside class="sidebar space-y-6">
3
- <% if available_modes.length > 1 %>
4
- <%= render "markdowndocs/docs/mode_switcher",
5
- current_mode: current_mode,
6
- available_modes: available_modes %>
7
- <% end %>
8
-
9
3
  <% if toc_items.length >= 3 %>
10
4
  <div class="bg-white dark:bg-slate-800 rounded-lg shadow-sm p-6">
11
5
  <nav aria-label="Table of Contents">
@@ -13,7 +7,10 @@
13
7
  <ul class="space-y-2">
14
8
  <% toc_items.each do |item| %>
15
9
  <li class="<%= 'ml-4' if item[:level] == 3 %>">
16
- <a href="#<%= item[:slug] %>" class="text-sm text-gray-700 dark:text-slate-300 hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors block py-1">
10
+ <%# min-h-11 (44px) meets WCAG 2.5.5 AAA target size sidebar TOC links
11
+ measured ~20px. flex + items-center keeps the label vertically
12
+ centered in the taller hit area. %>
13
+ <a href="#<%= item[:slug] %>" class="text-sm text-gray-700 dark:text-slate-300 hover:text-indigo-700 dark:hover:text-indigo-300 transition-colors flex min-h-11 items-center">
17
14
  <%= item[:text] %>
18
15
  </a>
19
16
  </li>
@@ -29,7 +26,8 @@
29
26
  <ul class="space-y-3">
30
27
  <% related_docs.each do |related_doc| %>
31
28
  <li>
32
- <%= link_to related_doc.title, markdowndocs.doc_path(related_doc.slug), class: "text-sm text-indigo-700 dark:text-indigo-300 hover:text-indigo-800 dark:hover:text-indigo-200 font-medium transition-colors" %>
29
+ <%# inline-flex min-h-11 (44px) meets WCAG 2.5.5 AAA target size. %>
30
+ <%= link_to related_doc.title, markdowndocs.doc_path(related_doc.slug), class: "text-sm text-indigo-700 dark:text-indigo-300 hover:text-indigo-800 dark:hover:text-indigo-200 font-medium transition-colors inline-flex min-h-11 items-center" %>
33
31
  <p class="text-xs text-gray-700 dark:text-slate-300 mt-1"><%= related_doc.description %></p>
34
32
  </li>
35
33
  <% end %>
@@ -6,6 +6,9 @@
6
6
  data-controller="docs-search"
7
7
  data-docs-search-index-url-value="<%= markdowndocs.search_index_path %>"
8
8
  <% end %>>
9
+ <%= render "markdowndocs/docs/docs_toolbar",
10
+ current_mode: @docs_mode,
11
+ available_modes: @available_modes %>
9
12
  <!-- Hero Section -->
10
13
  <div class="text-center mb-12">
11
14
  <h1 class="text-4xl font-bold text-gray-900 dark:text-slate-100 mb-4">Documentation</h1>
@@ -18,6 +18,10 @@
18
18
  <!-- Breadcrumb -->
19
19
  <%= render "markdowndocs/docs/breadcrumb", category: @doc.category, title: @doc.title %>
20
20
 
21
+ <%= render "markdowndocs/docs/docs_toolbar",
22
+ current_mode: @docs_mode,
23
+ available_modes: @available_modes %>
24
+
21
25
  <!-- Mobile navigation (hamburger dropdown, hidden on desktop) -->
22
26
  <div class="lg:hidden mb-6">
23
27
  <button
@@ -57,8 +61,6 @@
57
61
  <%= render "markdowndocs/docs/navigation",
58
62
  rendered_content: @rendered_content,
59
63
  related_docs: @related_docs,
60
- current_mode: @docs_mode,
61
- available_modes: @available_modes,
62
64
  toc_items: @toc_items %>
63
65
  </div>
64
66
  </div>
@@ -84,8 +86,6 @@
84
86
  <%= render "markdowndocs/docs/navigation",
85
87
  rendered_content: @rendered_content,
86
88
  related_docs: @related_docs,
87
- current_mode: @docs_mode,
88
- available_modes: @available_modes,
89
89
  toc_items: @toc_items %>
90
90
  </div>
91
91
  </div>
@@ -4,6 +4,8 @@ en:
4
4
  navigation_sidebar: "Navigation & Related Docs"
5
5
  viewing_mode: "Viewing Mode"
6
6
  select_viewing_mode: "Select documentation viewing mode"
7
+ mode_announcement: "Now viewing %{mode}."
8
+ no_counterpart_announcement: "No %{mode} version of this page — showing the %{mode} documentation."
7
9
  modes:
8
10
  guide: "User Guide"
9
11
  guide_description: "User-friendly explanations and step-by-step instructions"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Markdowndocs
4
- VERSION = "0.9.0"
4
+ VERSION = "0.11.0"
5
5
  end
data/mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "3.4.6"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markdowndocs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Chmura
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-06-23 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -75,6 +74,7 @@ executables: []
75
74
  extensions: []
76
75
  extra_rdoc_files: []
77
76
  files:
77
+ - ".tool-versions"
78
78
  - CHANGELOG.md
79
79
  - README.md
80
80
  - Rakefile
@@ -91,6 +91,7 @@ files:
91
91
  - app/views/layouts/markdowndocs/application.html.erb
92
92
  - app/views/markdowndocs/docs/_breadcrumb.html.erb
93
93
  - app/views/markdowndocs/docs/_card.html.erb
94
+ - app/views/markdowndocs/docs/_docs_toolbar.html.erb
94
95
  - app/views/markdowndocs/docs/_mode_switcher.html.erb
95
96
  - app/views/markdowndocs/docs/_navigation.html.erb
96
97
  - app/views/markdowndocs/docs/index.html.erb
@@ -104,6 +105,7 @@ files:
104
105
  - lib/markdowndocs/configuration.rb
105
106
  - lib/markdowndocs/engine.rb
106
107
  - lib/markdowndocs/version.rb
108
+ - mise.toml
107
109
  - sig/markdowndocs.rbs
108
110
  homepage: https://github.com/dschmura/markdowndocs
109
111
  licenses:
@@ -112,7 +114,6 @@ metadata:
112
114
  homepage_uri: https://github.com/dschmura/markdowndocs
113
115
  source_code_uri: https://github.com/dschmura/markdowndocs
114
116
  changelog_uri: https://github.com/dschmura/markdowndocs/blob/main/CHANGELOG.md
115
- post_install_message:
116
117
  rdoc_options: []
117
118
  require_paths:
118
119
  - lib
@@ -127,8 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
128
  - !ruby/object:Gem::Version
128
129
  version: '0'
129
130
  requirements: []
130
- rubygems_version: 3.4.19
131
- signing_key:
131
+ rubygems_version: 3.6.9
132
132
  specification_version: 4
133
133
  summary: A drop-in markdown documentation site for Rails apps
134
134
  test_files: []