docyard 0.6.0 → 0.8.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/.rubocop.yml +5 -1
- data/CHANGELOG.md +34 -1
- data/lib/docyard/build/asset_bundler.rb +22 -7
- data/lib/docyard/build/file_copier.rb +49 -27
- data/lib/docyard/build/sitemap_generator.rb +6 -6
- data/lib/docyard/build/static_generator.rb +82 -50
- data/lib/docyard/builder.rb +20 -10
- data/lib/docyard/cli.rb +6 -3
- data/lib/docyard/components/aliases.rb +29 -0
- data/lib/docyard/components/processors/callout_processor.rb +124 -0
- data/lib/docyard/components/processors/code_block_diff_preprocessor.rb +106 -0
- data/lib/docyard/components/processors/code_block_focus_preprocessor.rb +79 -0
- data/lib/docyard/components/processors/code_block_options_preprocessor.rb +78 -0
- data/lib/docyard/components/processors/code_block_processor.rb +175 -0
- data/lib/docyard/components/processors/code_snippet_import_preprocessor.rb +127 -0
- data/lib/docyard/components/processors/heading_anchor_processor.rb +39 -0
- data/lib/docyard/components/processors/icon_processor.rb +53 -0
- data/lib/docyard/components/processors/table_of_contents_processor.rb +68 -0
- data/lib/docyard/components/processors/table_wrapper_processor.rb +22 -0
- data/lib/docyard/components/processors/tabs_processor.rb +48 -0
- data/lib/docyard/components/support/code_block/feature_extractor.rb +117 -0
- data/lib/docyard/components/support/code_block/icon_detector.rb +44 -0
- data/lib/docyard/components/support/code_block/line_parser.rb +84 -0
- data/lib/docyard/components/support/code_block/line_wrapper.rb +50 -0
- data/lib/docyard/components/support/code_block/patterns.rb +55 -0
- data/lib/docyard/components/support/code_detector.rb +61 -0
- data/lib/docyard/components/support/tabs/icon_detector.rb +62 -0
- data/lib/docyard/components/support/tabs/parser.rb +195 -0
- data/lib/docyard/components/support/tabs/range_finder.rb +46 -0
- data/lib/docyard/config/branding_resolver.rb +183 -0
- data/lib/docyard/{constants.rb → config/constants.rb} +7 -4
- data/lib/docyard/config/validator.rb +122 -99
- data/lib/docyard/config.rb +38 -36
- data/lib/docyard/initializer.rb +15 -76
- data/lib/docyard/navigation/breadcrumb_builder.rb +133 -0
- data/lib/docyard/{prev_next_builder.rb → navigation/prev_next_builder.rb} +6 -3
- data/lib/docyard/navigation/sidebar/children_discoverer.rb +51 -0
- data/lib/docyard/navigation/sidebar/config_parser.rb +208 -0
- data/lib/docyard/navigation/sidebar/file_resolver.rb +78 -0
- data/lib/docyard/{sidebar → navigation/sidebar}/file_system_scanner.rb +2 -1
- data/lib/docyard/navigation/sidebar/item.rb +96 -0
- data/lib/docyard/navigation/sidebar/local_config_loader.rb +51 -0
- data/lib/docyard/navigation/sidebar/metadata_extractor.rb +69 -0
- data/lib/docyard/navigation/sidebar/metadata_reader.rb +47 -0
- data/lib/docyard/navigation/sidebar/path_prefixer.rb +34 -0
- data/lib/docyard/navigation/sidebar/renderer.rb +144 -0
- data/lib/docyard/navigation/sidebar/sorter.rb +21 -0
- data/lib/docyard/navigation/sidebar/tree_builder.rb +139 -0
- data/lib/docyard/navigation/sidebar/tree_filter.rb +55 -0
- data/lib/docyard/navigation/sidebar_builder.rb +159 -0
- data/lib/docyard/rendering/icon_helpers.rb +13 -0
- data/lib/docyard/{icons → rendering/icons}/phosphor.rb +26 -1
- data/lib/docyard/{markdown.rb → rendering/markdown.rb} +19 -13
- data/lib/docyard/rendering/renderer.rb +163 -0
- data/lib/docyard/rendering/template_resolver.rb +172 -0
- data/lib/docyard/routing/fallback_resolver.rb +92 -0
- data/lib/docyard/search/build_indexer.rb +74 -0
- data/lib/docyard/search/dev_indexer.rb +155 -0
- data/lib/docyard/search/pagefind_support.rb +33 -0
- data/lib/docyard/{asset_handler.rb → server/asset_handler.rb} +24 -19
- data/lib/docyard/{server.rb → server/dev_server.rb} +32 -9
- data/lib/docyard/server/pagefind_handler.rb +63 -0
- data/lib/docyard/{preview_server.rb → server/preview_server.rb} +2 -2
- data/lib/docyard/server/rack_application.rb +192 -0
- data/lib/docyard/server/resolution_result.rb +29 -0
- data/lib/docyard/{router.rb → server/router.rb} +4 -4
- data/lib/docyard/templates/assets/css/code.css +18 -51
- data/lib/docyard/templates/assets/css/components/breadcrumbs.css +143 -0
- data/lib/docyard/templates/assets/css/components/callout.css +67 -67
- data/lib/docyard/templates/assets/css/components/code-block.css +180 -282
- data/lib/docyard/templates/assets/css/components/heading-anchor.css +28 -15
- data/lib/docyard/templates/assets/css/components/icon.css +0 -1
- data/lib/docyard/templates/assets/css/components/logo.css +0 -2
- data/lib/docyard/templates/assets/css/components/nav-menu.css +237 -0
- data/lib/docyard/templates/assets/css/components/navigation.css +186 -167
- data/lib/docyard/templates/assets/css/components/prev-next.css +76 -47
- data/lib/docyard/templates/assets/css/components/search.css +561 -0
- data/lib/docyard/templates/assets/css/components/tab-bar.css +163 -0
- data/lib/docyard/templates/assets/css/components/table-of-contents.css +127 -114
- data/lib/docyard/templates/assets/css/components/tabs.css +119 -160
- data/lib/docyard/templates/assets/css/components/theme-toggle.css +48 -44
- data/lib/docyard/templates/assets/css/landing.css +815 -0
- data/lib/docyard/templates/assets/css/layout.css +503 -87
- data/lib/docyard/templates/assets/css/main.css +1 -3
- data/lib/docyard/templates/assets/css/markdown.css +111 -93
- data/lib/docyard/templates/assets/css/reset.css +0 -3
- data/lib/docyard/templates/assets/css/typography.css +43 -41
- data/lib/docyard/templates/assets/css/variables.css +268 -208
- data/lib/docyard/templates/assets/favicon.svg +7 -8
- data/lib/docyard/templates/assets/fonts/Inter-Variable.ttf +0 -0
- data/lib/docyard/templates/assets/js/components/code-block.js +24 -42
- data/lib/docyard/templates/assets/js/components/heading-anchor.js +26 -24
- data/lib/docyard/templates/assets/js/components/navigation.js +181 -70
- data/lib/docyard/templates/assets/js/components/search.js +610 -0
- data/lib/docyard/templates/assets/js/components/sidebar-toggle.js +29 -0
- data/lib/docyard/templates/assets/js/components/tab-navigation.js +145 -0
- data/lib/docyard/templates/assets/js/components/table-of-contents.js +153 -66
- data/lib/docyard/templates/assets/js/components/tabs.js +31 -69
- data/lib/docyard/templates/assets/js/theme.js +0 -3
- data/lib/docyard/templates/assets/logo-dark.svg +8 -2
- data/lib/docyard/templates/assets/logo.svg +7 -4
- data/lib/docyard/templates/config/docyard.yml.erb +37 -34
- data/lib/docyard/templates/errors/404.html.erb +1 -1
- data/lib/docyard/templates/errors/500.html.erb +1 -1
- data/lib/docyard/templates/layouts/default.html.erb +19 -56
- data/lib/docyard/templates/layouts/splash.html.erb +176 -0
- data/lib/docyard/templates/partials/_breadcrumbs.html.erb +24 -0
- data/lib/docyard/templates/partials/_code_block.html.erb +6 -4
- data/lib/docyard/templates/partials/_doc_footer.html.erb +25 -0
- data/lib/docyard/templates/partials/_features.html.erb +15 -0
- data/lib/docyard/templates/partials/_footer.html.erb +42 -0
- data/lib/docyard/templates/partials/_head.html.erb +22 -0
- data/lib/docyard/templates/partials/_header.html.erb +49 -0
- data/lib/docyard/templates/partials/_heading_anchor.html.erb +3 -1
- data/lib/docyard/templates/partials/_hero.html.erb +27 -0
- data/lib/docyard/templates/partials/_nav_group.html.erb +25 -11
- data/lib/docyard/templates/partials/_nav_leaf.html.erb +1 -1
- data/lib/docyard/templates/partials/_nav_menu.html.erb +42 -0
- data/lib/docyard/templates/partials/_nav_nested_section.html.erb +11 -0
- data/lib/docyard/templates/partials/_nav_section.html.erb +1 -1
- data/lib/docyard/templates/partials/_prev_next.html.erb +9 -3
- data/lib/docyard/templates/partials/_scripts.html.erb +7 -0
- data/lib/docyard/templates/partials/_search_modal.html.erb +41 -0
- data/lib/docyard/templates/partials/_search_trigger.html.erb +18 -0
- data/lib/docyard/templates/partials/_sidebar.html.erb +21 -4
- data/lib/docyard/templates/partials/_tab_bar.html.erb +25 -0
- data/lib/docyard/templates/partials/_table_of_contents.html.erb +12 -12
- data/lib/docyard/templates/partials/_table_of_contents_toggle.html.erb +1 -3
- data/lib/docyard/templates/partials/_tabs.html.erb +2 -2
- data/lib/docyard/templates/partials/_theme_toggle.html.erb +2 -11
- data/lib/docyard/utils/html_helpers.rb +14 -0
- data/lib/docyard/utils/path_resolver.rb +2 -1
- data/lib/docyard/utils/url_helpers.rb +20 -0
- data/lib/docyard/version.rb +1 -1
- data/lib/docyard.rb +22 -15
- metadata +89 -50
- data/lib/docyard/components/callout_processor.rb +0 -121
- data/lib/docyard/components/code_block_diff_preprocessor.rb +0 -104
- data/lib/docyard/components/code_block_feature_extractor.rb +0 -113
- data/lib/docyard/components/code_block_focus_preprocessor.rb +0 -77
- data/lib/docyard/components/code_block_icon_detector.rb +0 -40
- data/lib/docyard/components/code_block_line_wrapper.rb +0 -46
- data/lib/docyard/components/code_block_options_preprocessor.rb +0 -76
- data/lib/docyard/components/code_block_patterns.rb +0 -51
- data/lib/docyard/components/code_block_processor.rb +0 -176
- data/lib/docyard/components/code_detector.rb +0 -59
- data/lib/docyard/components/code_line_parser.rb +0 -80
- data/lib/docyard/components/code_snippet_import_preprocessor.rb +0 -125
- data/lib/docyard/components/heading_anchor_processor.rb +0 -34
- data/lib/docyard/components/icon_detector.rb +0 -57
- data/lib/docyard/components/icon_processor.rb +0 -51
- data/lib/docyard/components/table_of_contents_processor.rb +0 -64
- data/lib/docyard/components/table_wrapper_processor.rb +0 -18
- data/lib/docyard/components/tabs_parser.rb +0 -191
- data/lib/docyard/components/tabs_processor.rb +0 -44
- data/lib/docyard/components/tabs_range_finder.rb +0 -42
- data/lib/docyard/rack_application.rb +0 -172
- data/lib/docyard/renderer.rb +0 -120
- data/lib/docyard/routing/resolution_result.rb +0 -31
- data/lib/docyard/sidebar/config_parser.rb +0 -180
- data/lib/docyard/sidebar/item.rb +0 -58
- data/lib/docyard/sidebar/renderer.rb +0 -137
- data/lib/docyard/sidebar/tree_builder.rb +0 -59
- data/lib/docyard/sidebar_builder.rb +0 -102
- data/lib/docyard/templates/markdown/getting-started/installation.md.erb +0 -77
- data/lib/docyard/templates/markdown/guides/configuration.md.erb +0 -202
- data/lib/docyard/templates/markdown/guides/markdown-features.md.erb +0 -247
- data/lib/docyard/templates/markdown/index.md.erb +0 -82
- /data/lib/docyard/{sidebar → navigation/sidebar}/title_extractor.rb +0 -0
- /data/lib/docyard/{icons → rendering/icons}/LICENSE.phosphor +0 -0
- /data/lib/docyard/{icons → rendering/icons}/file_types.rb +0 -0
- /data/lib/docyard/{icons.rb → rendering/icons.rb} +0 -0
- /data/lib/docyard/{language_mapping.rb → rendering/language_mapping.rb} +0 -0
- /data/lib/docyard/{file_watcher.rb → server/file_watcher.rb} +0 -0
- /data/lib/docyard/{errors.rb → utils/errors.rb} +0 -0
- /data/lib/docyard/{logging.rb → utils/logging.rb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 77d317cd25d544eef47b5bdcecb0515b8937da93b347d39cac6fd1f87bb43b19
|
|
4
|
+
data.tar.gz: bf97d9449013ba8bf370682271990f64b2c2092bfdc9bf0deb99cf2b67056cc2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2e30597716798800240f4436c423284d1972fe5fa0abf1de8007b3279dde0a87ef32210cb830c84769c15db0c82e6c372337ae06baaecdb71fa866342c9697a3
|
|
7
|
+
data.tar.gz: f0ae1edf5937153c9ed3ccb1cc7c599c7f650e16470ad976ef0918c09bc030502ecf89dad6a8a7c79ee8055530b61a65d556bbfd147e08a86349a2475777ee54
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-01-13
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Landing Pages** - Hero sections, feature grids, and custom footer layouts for documentation homepages (#45)
|
|
14
|
+
- **Tab Navigation** - Top-level navigation tabs for organizing documentation into sections like Guide, API, Components (#52)
|
|
15
|
+
- **Header CTAs** - Configurable call-to-action buttons in the header with primary/secondary variants (#51)
|
|
16
|
+
- **Breadcrumbs** - Path navigation with auto-truncation for deep nesting and configurable via `navigation.breadcrumbs` (#54)
|
|
17
|
+
- **Doc Page Footer** - Social icons, "Built with Docyard" attribution, and copyright text in TOC column (#55)
|
|
18
|
+
- **Auto-detect Branding** - Automatic logo and favicon detection from `docs/public/` directory (#49)
|
|
19
|
+
- **Social Icon Mapping** - 16 social platform icons with automatic platform-to-icon mapping (#55)
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- **Sidebar Overhaul** - Per-section `_sidebar.yml` files, improved collapsible behavior, and better active state handling (#50, #53)
|
|
23
|
+
- **Config Schema** - Reorganized configuration with `branding`, `navigation`, and `socials` sections (#48)
|
|
24
|
+
- **Sidebar Convention** - Section-based sidebar configuration in `docs/<section>/_sidebar.yml` (#47)
|
|
25
|
+
- **UI Refresh** - Updated typography, spacing, and visual consistency across components (#44)
|
|
26
|
+
- **Logo Update** - New logo with cyan accent and dark mode support (#46)
|
|
27
|
+
|
|
28
|
+
## [0.7.0] - 2026-01-01
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **Full-text Search** - Pagefind-powered search with Cmd/Ctrl+K modal, keyboard navigation, and highlighting (#41)
|
|
32
|
+
- **Search Configuration** - Customize placeholder text, enable/disable search, and exclude paths via `docyard.yml` (#41)
|
|
33
|
+
- **Dev Server Search** - Opt-in search indexing during development with `--search` flag (#41)
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
- Major codebase reorganization for improved maintainability (#42)
|
|
37
|
+
- Components reorganized into `processors/` and `support/` subdirectories (#42)
|
|
38
|
+
- Consolidated `server/`, `rendering/`, `navigation/`, `config/`, and `search/` modules (#42)
|
|
39
|
+
- Extracted shared utilities into `utils/` module (#42)
|
|
40
|
+
|
|
10
41
|
## [0.6.0] - 2025-12-25
|
|
11
42
|
|
|
12
43
|
### Added
|
|
@@ -109,7 +140,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
109
140
|
- Initial gem structure
|
|
110
141
|
- Project scaffolding
|
|
111
142
|
|
|
112
|
-
[Unreleased]: https://github.com/sanifhimani/docyard/compare/v0.
|
|
143
|
+
[Unreleased]: https://github.com/sanifhimani/docyard/compare/v0.8.0...HEAD
|
|
144
|
+
[0.8.0]: https://github.com/sanifhimani/docyard/compare/v0.7.0...v0.8.0
|
|
145
|
+
[0.7.0]: https://github.com/sanifhimani/docyard/compare/v0.6.0...v0.7.0
|
|
113
146
|
[0.6.0]: https://github.com/sanifhimani/docyard/compare/v0.5.0...v0.6.0
|
|
114
147
|
[0.5.0]: https://github.com/sanifhimani/docyard/compare/v0.4.0...v0.5.0
|
|
115
148
|
[0.4.0]: https://github.com/sanifhimani/docyard/compare/v0.3.0...v0.4.0
|
|
@@ -35,6 +35,8 @@ module Docyard
|
|
|
35
35
|
main_css = File.read(File.join(ASSETS_PATH, "css", "main.css"))
|
|
36
36
|
css_content = resolve_css_imports(main_css)
|
|
37
37
|
minified = CSSminify.compress(css_content)
|
|
38
|
+
minified = fix_calc_whitespace(minified)
|
|
39
|
+
minified = fix_css_math_functions(minified)
|
|
38
40
|
hash = generate_hash(minified)
|
|
39
41
|
|
|
40
42
|
write_bundled_asset(minified, hash, "css")
|
|
@@ -43,6 +45,19 @@ module Docyard
|
|
|
43
45
|
hash
|
|
44
46
|
end
|
|
45
47
|
|
|
48
|
+
def fix_calc_whitespace(css)
|
|
49
|
+
css
|
|
50
|
+
.gsub(/\)\+(?!\s)/, ") + ")
|
|
51
|
+
.gsub(/\)-(?![-\s])/, ") - ")
|
|
52
|
+
.gsub(/(\d[a-z]*)\+(?=[\w(])/, '\1 + ')
|
|
53
|
+
.gsub(/([lch])\+(?=[\d.])/, '\1 + ')
|
|
54
|
+
.gsub(/([lch])-(?=[\d.])/, '\1 - ')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def fix_css_math_functions(css)
|
|
58
|
+
css.gsub(/\bmax\(0,/, "max(0px,").gsub(/\bmin\(0,/, "min(0px,)")
|
|
59
|
+
end
|
|
60
|
+
|
|
46
61
|
def resolve_css_imports(css_content)
|
|
47
62
|
css_content.gsub(/@import url\('([^']+)'\);/) do |match|
|
|
48
63
|
import_file = Regexp.last_match(1)
|
|
@@ -92,8 +107,8 @@ module Docyard
|
|
|
92
107
|
end
|
|
93
108
|
|
|
94
109
|
def update_html_references(css_hash, js_hash)
|
|
95
|
-
html_files = Dir.glob(File.join(config.build.
|
|
96
|
-
base_url = normalize_base_url(config.build.
|
|
110
|
+
html_files = Dir.glob(File.join(config.build.output, "**", "*.html"))
|
|
111
|
+
base_url = normalize_base_url(config.build.base)
|
|
97
112
|
|
|
98
113
|
html_files.each do |file|
|
|
99
114
|
content = replace_asset_references(File.read(file), css_hash, js_hash, base_url)
|
|
@@ -104,15 +119,15 @@ module Docyard
|
|
|
104
119
|
end
|
|
105
120
|
|
|
106
121
|
def replace_asset_references(content, css_hash, js_hash, base_url)
|
|
107
|
-
content.gsub(%r{/
|
|
108
|
-
.gsub(%r{/
|
|
109
|
-
.gsub(%r{/
|
|
110
|
-
.gsub(%r{<script src="/
|
|
122
|
+
content.gsub(%r{/_docyard/css/main\.css}, "#{base_url}_docyard/bundle.#{css_hash}.css")
|
|
123
|
+
.gsub(%r{/_docyard/js/theme\.js}, "#{base_url}_docyard/bundle.#{js_hash}.js")
|
|
124
|
+
.gsub(%r{/_docyard/js/components\.js}, "")
|
|
125
|
+
.gsub(%r{<script src="/_docyard/js/reload\.js"></script>}, "")
|
|
111
126
|
end
|
|
112
127
|
|
|
113
128
|
def write_bundled_asset(content, hash, extension)
|
|
114
129
|
filename = "bundle.#{hash}.#{extension}"
|
|
115
|
-
output_path = File.join(config.build.
|
|
130
|
+
output_path = File.join(config.build.output, "_docyard", filename)
|
|
116
131
|
FileUtils.mkdir_p(File.dirname(output_path))
|
|
117
132
|
File.write(output_path, content)
|
|
118
133
|
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
module Docyard
|
|
4
4
|
module Build
|
|
5
5
|
class FileCopier
|
|
6
|
+
DOCYARD_OUTPUT_DIR = "_docyard"
|
|
7
|
+
|
|
6
8
|
attr_reader :config, :verbose
|
|
7
9
|
|
|
8
10
|
def initialize(config, verbose: false)
|
|
@@ -14,7 +16,7 @@ module Docyard
|
|
|
14
16
|
puts "\nCopying static assets..."
|
|
15
17
|
|
|
16
18
|
count = 0
|
|
17
|
-
count +=
|
|
19
|
+
count += copy_public_files
|
|
18
20
|
count += copy_branding_assets
|
|
19
21
|
|
|
20
22
|
log "[✓] Copied #{count} static files"
|
|
@@ -23,25 +25,22 @@ module Docyard
|
|
|
23
25
|
|
|
24
26
|
private
|
|
25
27
|
|
|
26
|
-
def
|
|
27
|
-
|
|
28
|
-
return 0 unless Dir.exist?(
|
|
29
|
-
|
|
30
|
-
output_assets_dir = File.join(config.build.output_dir, "assets")
|
|
31
|
-
FileUtils.mkdir_p(output_assets_dir)
|
|
28
|
+
def copy_public_files
|
|
29
|
+
public_dir = Constants::PUBLIC_DIR
|
|
30
|
+
return 0 unless Dir.exist?(public_dir)
|
|
32
31
|
|
|
33
|
-
files =
|
|
34
|
-
files.each { |file|
|
|
32
|
+
files = find_files_in_dir(public_dir)
|
|
33
|
+
files.each { |file| copy_single_file(file, "#{public_dir}/", config.build.output) }
|
|
35
34
|
|
|
36
|
-
log "[✓] Copied #{files.size}
|
|
35
|
+
log "[✓] Copied #{files.size} public files from #{public_dir}/" if files.any?
|
|
37
36
|
files.size
|
|
38
37
|
end
|
|
39
38
|
|
|
40
|
-
def
|
|
41
|
-
Dir.glob(File.join(
|
|
39
|
+
def find_files_in_dir(dir)
|
|
40
|
+
Dir.glob(File.join(dir, "**", "*")).select { |f| File.file?(f) }
|
|
42
41
|
end
|
|
43
42
|
|
|
44
|
-
def
|
|
43
|
+
def copy_single_file(file, prefix, output_dir)
|
|
45
44
|
relative_path = file.delete_prefix(prefix)
|
|
46
45
|
dest_path = File.join(output_dir, relative_path)
|
|
47
46
|
|
|
@@ -60,26 +59,49 @@ module Docyard
|
|
|
60
59
|
end
|
|
61
60
|
|
|
62
61
|
def copy_default_branding_assets
|
|
63
|
-
templates_assets =
|
|
64
|
-
count =
|
|
62
|
+
templates_assets = templates_assets_path
|
|
63
|
+
count = copy_branding_files(templates_assets)
|
|
64
|
+
count + copy_fonts(templates_assets)
|
|
65
|
+
end
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
def templates_assets_path
|
|
68
|
+
File.join(__dir__, "..", "templates", "assets")
|
|
69
|
+
end
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
def copy_branding_files(templates_assets)
|
|
72
|
+
branding_files = %w[logo.svg logo-dark.svg favicon.svg]
|
|
73
|
+
branding_files.sum { |asset_file| copy_asset_to_docyard(templates_assets, asset_file, "default branding") }
|
|
74
|
+
end
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
def copy_asset_to_docyard(source_dir, filename, label)
|
|
77
|
+
source_path = File.join(source_dir, filename)
|
|
78
|
+
return 0 unless File.exist?(source_path)
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
dest_path = File.join(config.build.output, DOCYARD_OUTPUT_DIR, filename)
|
|
81
|
+
FileUtils.mkdir_p(File.dirname(dest_path))
|
|
82
|
+
FileUtils.cp(source_path, dest_path)
|
|
83
|
+
log " Copied #{label}: #{filename}" if verbose
|
|
84
|
+
1
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def copy_fonts(templates_assets)
|
|
88
|
+
fonts_dir = File.join(templates_assets, "fonts")
|
|
89
|
+
return 0 unless Dir.exist?(fonts_dir)
|
|
90
|
+
|
|
91
|
+
font_files = Dir.glob(File.join(fonts_dir, "*")).select { |f| File.file?(f) }
|
|
92
|
+
font_files.sum { |font_file| copy_single_font(font_file) }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def copy_single_font(font_file)
|
|
96
|
+
dest_path = File.join(config.build.output, DOCYARD_OUTPUT_DIR, "fonts", File.basename(font_file))
|
|
97
|
+
FileUtils.mkdir_p(File.dirname(dest_path))
|
|
98
|
+
FileUtils.cp(font_file, dest_path)
|
|
99
|
+
log " Copied font: #{File.basename(font_file)}" if verbose
|
|
100
|
+
1
|
|
79
101
|
end
|
|
80
102
|
|
|
81
103
|
def copy_user_branding_assets
|
|
82
|
-
%w[logo
|
|
104
|
+
%w[logo favicon].sum { |asset_key| copy_single_branding_asset(asset_key) }
|
|
83
105
|
end
|
|
84
106
|
|
|
85
107
|
def copy_single_branding_asset(asset_key)
|
|
@@ -89,7 +111,7 @@ module Docyard
|
|
|
89
111
|
full_path = File.join("docs", asset_path)
|
|
90
112
|
return 0 unless File.exist?(full_path)
|
|
91
113
|
|
|
92
|
-
dest_path = File.join(config.build.
|
|
114
|
+
dest_path = File.join(config.build.output, asset_path)
|
|
93
115
|
FileUtils.mkdir_p(File.dirname(dest_path))
|
|
94
116
|
FileUtils.cp(full_path, dest_path)
|
|
95
117
|
|
|
@@ -15,7 +15,7 @@ module Docyard
|
|
|
15
15
|
urls = collect_urls
|
|
16
16
|
sitemap_content = build_sitemap(urls)
|
|
17
17
|
|
|
18
|
-
output_path = File.join(config.build.
|
|
18
|
+
output_path = File.join(config.build.output, "sitemap.xml")
|
|
19
19
|
File.write(output_path, sitemap_content)
|
|
20
20
|
|
|
21
21
|
puts "[✓] Generated sitemap.xml (#{urls.size} URLs)"
|
|
@@ -24,10 +24,10 @@ module Docyard
|
|
|
24
24
|
private
|
|
25
25
|
|
|
26
26
|
def collect_urls
|
|
27
|
-
html_files = Dir.glob(File.join(config.build.
|
|
27
|
+
html_files = Dir.glob(File.join(config.build.output, "**", "index.html"))
|
|
28
28
|
|
|
29
29
|
html_files.map do |file|
|
|
30
|
-
relative_path = file.delete_prefix(config.build.
|
|
30
|
+
relative_path = file.delete_prefix(config.build.output).delete_suffix("/index.html")
|
|
31
31
|
url_path = relative_path.empty? ? "/" : relative_path
|
|
32
32
|
lastmod = File.mtime(file).utc.iso8601
|
|
33
33
|
|
|
@@ -36,15 +36,15 @@ module Docyard
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def build_sitemap(urls)
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
base = config.build.base
|
|
40
|
+
base = base.chop if base.end_with?("/")
|
|
41
41
|
|
|
42
42
|
xml = ['<?xml version="1.0" encoding="UTF-8"?>']
|
|
43
43
|
xml << '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
|
|
44
44
|
|
|
45
45
|
urls.each do |url|
|
|
46
46
|
xml << " <url>"
|
|
47
|
-
xml << " <loc>#{
|
|
47
|
+
xml << " <loc>#{base}#{url[:loc]}</loc>"
|
|
48
48
|
xml << " <lastmod>#{url[:lastmod]}</lastmod>"
|
|
49
49
|
xml << " </url>"
|
|
50
50
|
end
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "tty-progressbar"
|
|
4
|
+
require_relative "../rendering/template_resolver"
|
|
5
|
+
require_relative "../navigation/prev_next_builder"
|
|
6
|
+
require_relative "../navigation/breadcrumb_builder"
|
|
4
7
|
|
|
5
8
|
module Docyard
|
|
6
9
|
module Build
|
|
@@ -10,15 +13,17 @@ module Docyard
|
|
|
10
13
|
def initialize(config, verbose: false)
|
|
11
14
|
@config = config
|
|
12
15
|
@verbose = verbose
|
|
13
|
-
@renderer = Renderer.new(base_url: config.build.
|
|
16
|
+
@renderer = Renderer.new(base_url: config.build.base, config: config)
|
|
14
17
|
end
|
|
15
18
|
|
|
16
19
|
def generate
|
|
20
|
+
copy_custom_landing_page if custom_landing_page?
|
|
21
|
+
|
|
17
22
|
markdown_files = collect_markdown_files
|
|
18
23
|
puts "\n[✓] Found #{markdown_files.size} markdown files"
|
|
19
24
|
|
|
20
25
|
progress = TTY::ProgressBar.new(
|
|
21
|
-
"Generating pages [:bar] :current/:total (:percent
|
|
26
|
+
"Generating pages [:bar] :current/:total (:percent)",
|
|
22
27
|
total: markdown_files.size,
|
|
23
28
|
width: 50
|
|
24
29
|
)
|
|
@@ -33,24 +38,72 @@ module Docyard
|
|
|
33
38
|
|
|
34
39
|
private
|
|
35
40
|
|
|
41
|
+
def custom_landing_page?
|
|
42
|
+
File.file?("docs/index.html")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def copy_custom_landing_page
|
|
46
|
+
output_path = File.join(config.build.output, "index.html")
|
|
47
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
|
48
|
+
FileUtils.cp("docs/index.html", output_path)
|
|
49
|
+
log "[✓] Copied custom landing page (index.html)"
|
|
50
|
+
end
|
|
51
|
+
|
|
36
52
|
def collect_markdown_files
|
|
37
|
-
Dir.glob(File.join("docs", "**", "*.md"))
|
|
53
|
+
files = Dir.glob(File.join("docs", "**", "*.md"))
|
|
54
|
+
files.reject! { |f| f == "docs/index.md" } if custom_landing_page?
|
|
55
|
+
files
|
|
38
56
|
end
|
|
39
57
|
|
|
40
58
|
def generate_page(markdown_file_path)
|
|
41
59
|
output_path = determine_output_path(markdown_file_path)
|
|
42
60
|
current_path = determine_current_path(markdown_file_path)
|
|
43
61
|
|
|
44
|
-
|
|
45
|
-
html_content =
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
html_content = render_markdown_file(markdown_file_path, current_path)
|
|
63
|
+
html_content = apply_search_exclusion(html_content, current_path)
|
|
64
|
+
write_output(output_path, html_content)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def apply_search_exclusion(html_content, current_path)
|
|
68
|
+
return html_content unless excluded_from_search?(current_path)
|
|
69
|
+
|
|
70
|
+
html_content.gsub("data-pagefind-body", "data-pagefind-ignore")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def excluded_from_search?(path)
|
|
74
|
+
exclude_patterns = config.search.exclude || []
|
|
75
|
+
exclude_patterns.any? do |pattern|
|
|
76
|
+
next false unless pattern.start_with?("/")
|
|
77
|
+
|
|
78
|
+
File.fnmatch(pattern, path, File::FNM_PATHNAME)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
50
81
|
|
|
82
|
+
def render_markdown_file(markdown_file_path, current_path)
|
|
83
|
+
markdown = Markdown.new(File.read(markdown_file_path))
|
|
84
|
+
template_resolver = TemplateResolver.new(markdown.frontmatter, config.data)
|
|
85
|
+
branding = branding_options
|
|
86
|
+
|
|
87
|
+
navigation = build_navigation_html(template_resolver, current_path, markdown, branding[:header_ctas])
|
|
88
|
+
renderer.render_file(markdown_file_path, **navigation, branding: branding,
|
|
89
|
+
template_options: template_resolver.to_options,
|
|
90
|
+
current_path: current_path)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def build_navigation_html(template_resolver, current_path, markdown, header_ctas)
|
|
94
|
+
return { sidebar_html: "", prev_next_html: "", breadcrumbs: nil } unless template_resolver.show_sidebar?
|
|
95
|
+
|
|
96
|
+
sidebar_builder = build_sidebar_instance(current_path, header_ctas)
|
|
97
|
+
{
|
|
98
|
+
sidebar_html: sidebar_builder.to_html,
|
|
99
|
+
prev_next_html: build_prev_next(sidebar_builder, current_path, markdown),
|
|
100
|
+
breadcrumbs: build_breadcrumbs(sidebar_builder.tree, current_path)
|
|
101
|
+
}
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def write_output(output_path, html_content)
|
|
51
105
|
FileUtils.mkdir_p(File.dirname(output_path))
|
|
52
106
|
File.write(output_path, html_content)
|
|
53
|
-
|
|
54
107
|
log "Generated: #{output_path}" if verbose
|
|
55
108
|
end
|
|
56
109
|
|
|
@@ -59,7 +112,7 @@ module Docyard
|
|
|
59
112
|
base_name = File.basename(relative_path, ".md")
|
|
60
113
|
dir_name = File.dirname(relative_path)
|
|
61
114
|
|
|
62
|
-
output_dir = config.build.
|
|
115
|
+
output_dir = config.build.output
|
|
63
116
|
|
|
64
117
|
if base_name == "index"
|
|
65
118
|
File.join(output_dir, dir_name, "index.html")
|
|
@@ -80,57 +133,36 @@ module Docyard
|
|
|
80
133
|
end
|
|
81
134
|
end
|
|
82
135
|
|
|
83
|
-
def
|
|
136
|
+
def build_sidebar_instance(current_path, header_ctas = [])
|
|
84
137
|
SidebarBuilder.new(
|
|
85
138
|
docs_path: "docs",
|
|
86
139
|
current_path: current_path,
|
|
87
|
-
config: config
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def branding_options
|
|
92
|
-
default_branding.merge(config_branding_options)
|
|
140
|
+
config: config,
|
|
141
|
+
header_ctas: header_ctas
|
|
142
|
+
)
|
|
93
143
|
end
|
|
94
144
|
|
|
95
|
-
def
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
display_logo: true,
|
|
103
|
-
display_title: true
|
|
104
|
-
}
|
|
145
|
+
def build_prev_next(sidebar_builder, current_path, markdown)
|
|
146
|
+
PrevNextBuilder.new(
|
|
147
|
+
sidebar_tree: sidebar_builder.tree,
|
|
148
|
+
current_path: current_path,
|
|
149
|
+
frontmatter: markdown.frontmatter,
|
|
150
|
+
config: {}
|
|
151
|
+
).to_html
|
|
105
152
|
end
|
|
106
153
|
|
|
107
|
-
def
|
|
108
|
-
|
|
109
|
-
branding = config.branding
|
|
154
|
+
def build_breadcrumbs(sidebar_tree, current_path)
|
|
155
|
+
return nil unless breadcrumbs_enabled?
|
|
110
156
|
|
|
111
|
-
|
|
112
|
-
site_title: site.title || Constants::DEFAULT_SITE_TITLE,
|
|
113
|
-
site_description: site.description || "",
|
|
114
|
-
logo: resolve_logo(branding.logo, branding.logo_dark),
|
|
115
|
-
logo_dark: resolve_logo_dark(branding.logo, branding.logo_dark),
|
|
116
|
-
favicon: branding.favicon
|
|
117
|
-
}.merge(appearance_options(branding.appearance))
|
|
157
|
+
BreadcrumbBuilder.new(sidebar_tree: sidebar_tree, current_path: current_path)
|
|
118
158
|
end
|
|
119
159
|
|
|
120
|
-
def
|
|
121
|
-
|
|
122
|
-
{
|
|
123
|
-
display_logo: appearance["logo"] != false,
|
|
124
|
-
display_title: appearance["title"] != false
|
|
125
|
-
}
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def resolve_logo(logo, logo_dark)
|
|
129
|
-
logo || logo_dark || Constants::DEFAULT_LOGO_PATH
|
|
160
|
+
def breadcrumbs_enabled?
|
|
161
|
+
config.navigation.breadcrumbs != false
|
|
130
162
|
end
|
|
131
163
|
|
|
132
|
-
def
|
|
133
|
-
|
|
164
|
+
def branding_options
|
|
165
|
+
BrandingResolver.new(config).resolve
|
|
134
166
|
end
|
|
135
167
|
|
|
136
168
|
def log(message)
|
data/lib/docyard/builder.rb
CHANGED
|
@@ -22,8 +22,9 @@ module Docyard
|
|
|
22
22
|
bundles_created = bundle_assets
|
|
23
23
|
assets_copied = copy_static_files
|
|
24
24
|
generate_seo_files
|
|
25
|
+
pages_indexed = generate_search_index
|
|
25
26
|
|
|
26
|
-
display_summary(pages_built, bundles_created, assets_copied)
|
|
27
|
+
display_summary(pages_built, bundles_created, assets_copied, pages_indexed)
|
|
27
28
|
true
|
|
28
29
|
rescue StandardError => e
|
|
29
30
|
error "Build failed: #{e.message}"
|
|
@@ -34,7 +35,7 @@ module Docyard
|
|
|
34
35
|
private
|
|
35
36
|
|
|
36
37
|
def prepare_output_directory
|
|
37
|
-
output_dir = config.build.
|
|
38
|
+
output_dir = config.build.output
|
|
38
39
|
|
|
39
40
|
if clean && Dir.exist?(output_dir)
|
|
40
41
|
log "[✓] Cleaning #{output_dir}/ directory"
|
|
@@ -67,29 +68,38 @@ module Docyard
|
|
|
67
68
|
sitemap_gen = Build::SitemapGenerator.new(config)
|
|
68
69
|
sitemap_gen.generate
|
|
69
70
|
|
|
70
|
-
File.write(File.join(config.build.
|
|
71
|
-
log "[
|
|
71
|
+
File.write(File.join(config.build.output, "robots.txt"), robots_txt_content)
|
|
72
|
+
log "[+] Generated robots.txt"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def generate_search_index
|
|
76
|
+
indexer = Search::BuildIndexer.new(config, verbose: verbose)
|
|
77
|
+
indexer.index
|
|
72
78
|
end
|
|
73
79
|
|
|
74
80
|
def robots_txt_content
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
base = config.build.base
|
|
82
|
+
base = "#{base}/" unless base.end_with?("/")
|
|
77
83
|
|
|
78
84
|
<<~ROBOTS
|
|
79
85
|
User-agent: *
|
|
80
86
|
Allow: /
|
|
81
87
|
|
|
82
|
-
Sitemap: #{
|
|
88
|
+
Sitemap: #{base}sitemap.xml
|
|
83
89
|
ROBOTS
|
|
84
90
|
end
|
|
85
91
|
|
|
86
|
-
def display_summary(pages, bundles, assets)
|
|
92
|
+
def display_summary(pages, bundles, assets, indexed = 0)
|
|
87
93
|
elapsed = Time.now - start_time
|
|
88
94
|
|
|
89
95
|
puts "\n#{'=' * 50}"
|
|
90
96
|
puts "Build complete in #{format('%.2f', elapsed)}s"
|
|
91
|
-
puts "Output: #{config.build.
|
|
92
|
-
|
|
97
|
+
puts "Output: #{config.build.output}/"
|
|
98
|
+
|
|
99
|
+
summary = "#{pages} pages, #{bundles} bundles, #{assets} static files"
|
|
100
|
+
summary += ", #{indexed} pages indexed" if indexed.positive?
|
|
101
|
+
puts summary
|
|
102
|
+
|
|
93
103
|
puts "=" * 50
|
|
94
104
|
end
|
|
95
105
|
|
data/lib/docyard/cli.rb
CHANGED
|
@@ -34,18 +34,21 @@ module Docyard
|
|
|
34
34
|
desc "preview", "Preview the built site locally"
|
|
35
35
|
method_option :port, type: :numeric, default: 4000, aliases: "-p", desc: "Port to run preview server on"
|
|
36
36
|
def preview
|
|
37
|
-
require_relative "preview_server"
|
|
37
|
+
require_relative "server/preview_server"
|
|
38
38
|
Docyard::PreviewServer.new(port: options[:port]).start
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
desc "serve", "Start the development server"
|
|
42
42
|
method_option :port, type: :numeric, default: 4200, aliases: "-p", desc: "Port to run the server on"
|
|
43
43
|
method_option :host, type: :string, default: "localhost", aliases: "-h", desc: "Host to bind the server to"
|
|
44
|
+
method_option :search, type: :boolean, default: false, aliases: "-s",
|
|
45
|
+
desc: "Enable search indexing (slower startup)"
|
|
44
46
|
def serve
|
|
45
|
-
require_relative "server"
|
|
47
|
+
require_relative "server/dev_server"
|
|
46
48
|
server = Docyard::Server.new(
|
|
47
49
|
port: options[:port],
|
|
48
|
-
host: options[:host]
|
|
50
|
+
host: options[:host],
|
|
51
|
+
search: options[:search]
|
|
49
52
|
)
|
|
50
53
|
server.start
|
|
51
54
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Docyard
|
|
4
|
+
module Components
|
|
5
|
+
CalloutProcessor = Processors::CalloutProcessor
|
|
6
|
+
CodeBlockProcessor = Processors::CodeBlockProcessor
|
|
7
|
+
CodeBlockDiffPreprocessor = Processors::CodeBlockDiffPreprocessor
|
|
8
|
+
CodeBlockFocusPreprocessor = Processors::CodeBlockFocusPreprocessor
|
|
9
|
+
CodeBlockOptionsPreprocessor = Processors::CodeBlockOptionsPreprocessor
|
|
10
|
+
CodeSnippetImportPreprocessor = Processors::CodeSnippetImportPreprocessor
|
|
11
|
+
HeadingAnchorProcessor = Processors::HeadingAnchorProcessor
|
|
12
|
+
IconProcessor = Processors::IconProcessor
|
|
13
|
+
TableOfContentsProcessor = Processors::TableOfContentsProcessor
|
|
14
|
+
TableWrapperProcessor = Processors::TableWrapperProcessor
|
|
15
|
+
TabsProcessor = Processors::TabsProcessor
|
|
16
|
+
|
|
17
|
+
CodeDetector = Support::CodeDetector
|
|
18
|
+
IconDetector = Support::Tabs::IconDetector
|
|
19
|
+
|
|
20
|
+
CodeBlockFeatureExtractor = Support::CodeBlock::FeatureExtractor
|
|
21
|
+
CodeBlockIconDetector = Support::CodeBlock::IconDetector
|
|
22
|
+
CodeBlockLineWrapper = Support::CodeBlock::LineWrapper
|
|
23
|
+
CodeBlockPatterns = Support::CodeBlock::Patterns
|
|
24
|
+
CodeLineParser = Support::CodeBlock::LineParser
|
|
25
|
+
|
|
26
|
+
TabsParser = Support::Tabs::Parser
|
|
27
|
+
TabsRangeFinder = Support::Tabs::RangeFinder
|
|
28
|
+
end
|
|
29
|
+
end
|