markdowndocs 0.3.0 → 0.4.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/CHANGELOG.md +14 -0
- data/app/assets/javascripts/markdowndocs/controllers/docs_search_controller.js +23 -12
- data/app/controllers/markdowndocs/application_controller.rb +12 -27
- data/app/controllers/markdowndocs/docs_controller.rb +2 -1
- data/app/models/markdowndocs/documentation.rb +7 -0
- data/app/views/layouts/markdowndocs/application.html.erb +22 -0
- data/lib/markdowndocs/configuration.rb +3 -1
- data/lib/markdowndocs/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b10065bc9db477eab3c5c118832bf1bf3d0b8c68d879c6b3b5bd324b0deb4ec3
|
|
4
|
+
data.tar.gz: 4696b2b0c2e906ae7875ba69b32279d222f717db45abbed0987bb335f2d1e55d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 81f260911757400e215ebdc586c40229032e381ee5fc445e6606509de5a8fa15e7d60ce5a22f2b33e110c4984f63f093ca9e78393935b1d3e5306002c9dfe9de
|
|
7
|
+
data.tar.gz: f41f6d08e1736a2d772a89e0d89a5f6d57d6da25342b1a426c0f9bd339f028280d9e1bb0814209ac43edea4823057392a2e2e18db7d52164d1363d0b8c22462e
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,18 @@ 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.3.0] - 2026-03-20
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Keywords frontmatter support (`keywords: [login, signin, ...]`) indexed by full-text search with highest boost (4x), improving search relevance for docs with explicit keyword tags.
|
|
13
|
+
|
|
14
|
+
## [0.2.3] - 2026-03-20
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Host app route helpers (e.g., `about_path`) no longer resolve against the engine namespace. Replaced `method_missing` delegation with explicit `define_method` overrides built lazily on first request via `before_action`.
|
|
19
|
+
|
|
8
20
|
## [0.2.2] - 2026-03-18
|
|
9
21
|
|
|
10
22
|
### Changed
|
|
@@ -84,6 +96,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
84
96
|
- i18n support for all UI strings
|
|
85
97
|
- Install generator (`rails generate markdowndocs:install`)
|
|
86
98
|
|
|
99
|
+
[0.3.0]: https://github.com/dschmura/markdowndocs/releases/tag/v0.3.0
|
|
100
|
+
[0.2.3]: https://github.com/dschmura/markdowndocs/releases/tag/v0.2.3
|
|
87
101
|
[0.2.2]: https://github.com/dschmura/markdowndocs/releases/tag/v0.2.2
|
|
88
102
|
[0.2.1]: https://github.com/dschmura/markdowndocs/releases/tag/v0.2.1
|
|
89
103
|
[0.2.0]: https://github.com/dschmura/markdowndocs/releases/tag/v0.2.0
|
|
@@ -23,10 +23,10 @@ export default class extends Controller {
|
|
|
23
23
|
const MiniSearch = (await this.loadMiniSearch()).default || (await this.loadMiniSearch())
|
|
24
24
|
|
|
25
25
|
this.miniSearch = new MiniSearch({
|
|
26
|
-
fields: ["title", "description", "content", "keywords"],
|
|
26
|
+
fields: ["title", "description", "content", "keywords", "code"],
|
|
27
27
|
storeFields: ["title", "description"],
|
|
28
28
|
searchOptions: {
|
|
29
|
-
boost: { title: 3, description: 2, keywords: 4 },
|
|
29
|
+
boost: { title: 3, description: 2, keywords: 4, code: 0.5 },
|
|
30
30
|
fuzzy: 0.2,
|
|
31
31
|
prefix: true
|
|
32
32
|
}
|
|
@@ -58,7 +58,7 @@ export default class extends Controller {
|
|
|
58
58
|
|
|
59
59
|
search() {
|
|
60
60
|
if (this.debounceTimer) clearTimeout(this.debounceTimer)
|
|
61
|
-
this.debounceTimer = setTimeout(() => this.performSearch(),
|
|
61
|
+
this.debounceTimer = setTimeout(() => this.performSearch(), 50)
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
performSearch() {
|
|
@@ -71,16 +71,21 @@ export default class extends Controller {
|
|
|
71
71
|
|
|
72
72
|
const results = this.miniSearch.search(query)
|
|
73
73
|
const matchingSlugs = new Set(results.map(r => r.id))
|
|
74
|
+
const scoreBySlug = new Map(results.map(r => [r.id, r.score]))
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
const slug = card.dataset.slug
|
|
77
|
-
card.classList.toggle("hidden", !matchingSlugs.has(slug))
|
|
78
|
-
})
|
|
79
|
-
|
|
76
|
+
// Reorder cards within each category by relevance score
|
|
80
77
|
this.categoryTargets.forEach(section => {
|
|
81
|
-
const cards = section.querySelectorAll("[data-docs-search-target='card']")
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
const cards = Array.from(section.querySelectorAll("[data-docs-search-target='card']"))
|
|
79
|
+
cards.forEach(card => {
|
|
80
|
+
const slug = card.dataset.slug
|
|
81
|
+
card.classList.toggle("hidden", !matchingSlugs.has(slug))
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
const visibleCards = cards.filter(c => !c.classList.contains("hidden"))
|
|
85
|
+
visibleCards.sort((a, b) => (scoreBySlug.get(b.dataset.slug) || 0) - (scoreBySlug.get(a.dataset.slug) || 0))
|
|
86
|
+
visibleCards.forEach(card => card.parentElement.appendChild(card))
|
|
87
|
+
|
|
88
|
+
section.classList.toggle("hidden", visibleCards.length === 0)
|
|
84
89
|
})
|
|
85
90
|
|
|
86
91
|
const hasResults = matchingSlugs.size > 0
|
|
@@ -91,7 +96,13 @@ export default class extends Controller {
|
|
|
91
96
|
|
|
92
97
|
showAll() {
|
|
93
98
|
this.cardTargets.forEach(card => card.classList.remove("hidden"))
|
|
94
|
-
this.categoryTargets.forEach(section =>
|
|
99
|
+
this.categoryTargets.forEach(section => {
|
|
100
|
+
section.classList.remove("hidden")
|
|
101
|
+
// Restore original order by slug
|
|
102
|
+
const cards = Array.from(section.querySelectorAll("[data-docs-search-target='card']"))
|
|
103
|
+
cards.sort((a, b) => a.dataset.slug.localeCompare(b.dataset.slug))
|
|
104
|
+
cards.forEach(card => card.parentElement.appendChild(card))
|
|
105
|
+
})
|
|
95
106
|
if (this.hasNoResultsTarget) {
|
|
96
107
|
this.noResultsTarget.classList.add("hidden")
|
|
97
108
|
}
|
|
@@ -4,19 +4,20 @@ module Markdowndocs
|
|
|
4
4
|
class ApplicationController < ::ApplicationController
|
|
5
5
|
protect_from_forgery with: :exception
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# Use the engine's own layout to avoid route helper conflicts.
|
|
8
|
+
# Host apps that shared their application layout with the engine
|
|
9
|
+
# would see route helpers (about_path, signout_path, etc.) resolve
|
|
10
|
+
# against the engine's namespace instead of the main app.
|
|
8
11
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# so about_path returns "/docs/about" instead of "/about".
|
|
12
|
+
# Host apps can customize by overriding this layout at:
|
|
13
|
+
# app/views/layouts/markdowndocs/application.html.erb
|
|
12
14
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
before_action :ensure_host_route_helpers
|
|
15
|
+
# The layout provides content_for blocks:
|
|
16
|
+
# :docs_header — rendered above main content (for nav/header)
|
|
17
|
+
# :docs_footer — rendered below main content (for footer)
|
|
18
|
+
# :head — injected into <head> (for extra stylesheets/scripts)
|
|
19
|
+
# :title — page title (defaults to "Documentation")
|
|
20
|
+
layout -> { Markdowndocs.config.layout }
|
|
20
21
|
|
|
21
22
|
# Support Rails 8 built-in authentication (allow_unauthenticated_access)
|
|
22
23
|
# without requiring it — works with any auth system or none at all
|
|
@@ -26,21 +27,5 @@ module Markdowndocs
|
|
|
26
27
|
|
|
27
28
|
# Resume session if the host app supports it (Rails 8 auth)
|
|
28
29
|
before_action :resume_session, if: -> { respond_to?(:resume_session, true) }
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
def ensure_host_route_helpers
|
|
33
|
-
return if self.class.instance_variable_get(:@host_routes_delegated)
|
|
34
|
-
|
|
35
|
-
helper_module = Module.new do
|
|
36
|
-
Rails.application.routes.named_routes.names.each do |name|
|
|
37
|
-
define_method(:"#{name}_path") { |*args, **kwargs| main_app.send(:"#{name}_path", *args, **kwargs) }
|
|
38
|
-
define_method(:"#{name}_url") { |*args, **kwargs| main_app.send(:"#{name}_url", *args, **kwargs) }
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
self.class.helper(helper_module)
|
|
43
|
-
self.class.instance_variable_set(:@host_routes_delegated, true)
|
|
44
|
-
end
|
|
45
30
|
end
|
|
46
31
|
end
|
|
@@ -98,6 +98,13 @@ module Markdowndocs
|
|
|
98
98
|
text.strip
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
+
# Returns text extracted from fenced code blocks for search indexing.
|
|
102
|
+
def code_content
|
|
103
|
+
parsed = parse_frontmatter
|
|
104
|
+
blocks = parsed[:markdown].scan(/```\w*\n([\s\S]*?)```/)
|
|
105
|
+
blocks.flatten.join(" ").gsub(/\s+/, " ").strip
|
|
106
|
+
end
|
|
107
|
+
|
|
101
108
|
private
|
|
102
109
|
|
|
103
110
|
def derive_slug
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<title><%= content_for(:title) || "Documentation" %></title>
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<%= csrf_meta_tags %>
|
|
7
|
+
<%= csp_meta_tag %>
|
|
8
|
+
<%= yield :head %>
|
|
9
|
+
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" rescue nil %>
|
|
10
|
+
<%= javascript_importmap_tags rescue nil %>
|
|
11
|
+
</head>
|
|
12
|
+
|
|
13
|
+
<body class="min-h-screen flex flex-col bg-gray-50">
|
|
14
|
+
<%= yield :docs_header %>
|
|
15
|
+
|
|
16
|
+
<main id="main-content" role="main" class="flex-1">
|
|
17
|
+
<%= yield %>
|
|
18
|
+
</main>
|
|
19
|
+
|
|
20
|
+
<%= yield :docs_footer %>
|
|
21
|
+
</body>
|
|
22
|
+
</html>
|
|
@@ -4,7 +4,8 @@ module Markdowndocs
|
|
|
4
4
|
class Configuration
|
|
5
5
|
attr_accessor :docs_path, :categories, :modes, :default_mode,
|
|
6
6
|
:markdown_options, :rouge_theme, :cache_expiry,
|
|
7
|
-
:user_mode_resolver, :user_mode_saver, :search_enabled
|
|
7
|
+
:user_mode_resolver, :user_mode_saver, :search_enabled,
|
|
8
|
+
:layout
|
|
8
9
|
|
|
9
10
|
def initialize
|
|
10
11
|
@docs_path = nil # Resolved lazily so Rails.root is available
|
|
@@ -17,6 +18,7 @@ module Markdowndocs
|
|
|
17
18
|
@user_mode_resolver = nil
|
|
18
19
|
@user_mode_saver = nil
|
|
19
20
|
@search_enabled = false
|
|
21
|
+
@layout = "markdowndocs/application"
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
# Lazily resolve docs_path so Rails.root is available
|
data/lib/markdowndocs/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: markdowndocs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dave Chmura
|
|
@@ -87,6 +87,7 @@ files:
|
|
|
87
87
|
- app/helpers/markdowndocs/docs_helper.rb
|
|
88
88
|
- app/models/markdowndocs/documentation.rb
|
|
89
89
|
- app/services/markdowndocs/markdown_renderer.rb
|
|
90
|
+
- app/views/layouts/markdowndocs/application.html.erb
|
|
90
91
|
- app/views/markdowndocs/docs/_breadcrumb.html.erb
|
|
91
92
|
- app/views/markdowndocs/docs/_card.html.erb
|
|
92
93
|
- app/views/markdowndocs/docs/_mode_switcher.html.erb
|