docyard 0.7.0 → 0.9.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 +43 -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 +85 -12
- data/lib/docyard/builder.rb +6 -6
- data/lib/docyard/components/aliases.rb +12 -0
- data/lib/docyard/components/processors/abbreviation_processor.rb +72 -0
- data/lib/docyard/components/processors/accordion_processor.rb +81 -0
- data/lib/docyard/components/processors/badge_processor.rb +72 -0
- data/lib/docyard/components/processors/callout_processor.rb +8 -2
- data/lib/docyard/components/processors/cards_processor.rb +100 -0
- data/lib/docyard/components/processors/code_block_options_preprocessor.rb +23 -2
- data/lib/docyard/components/processors/code_block_processor.rb +6 -0
- data/lib/docyard/components/processors/code_group_processor.rb +198 -0
- data/lib/docyard/components/processors/code_snippet_import_preprocessor.rb +6 -1
- data/lib/docyard/components/processors/custom_anchor_processor.rb +42 -0
- data/lib/docyard/components/processors/file_tree_processor.rb +151 -0
- data/lib/docyard/components/processors/image_caption_processor.rb +96 -0
- data/lib/docyard/components/processors/include_processor.rb +86 -0
- data/lib/docyard/components/processors/steps_processor.rb +89 -0
- data/lib/docyard/components/processors/tabs_processor.rb +9 -1
- data/lib/docyard/components/processors/tooltip_processor.rb +57 -0
- data/lib/docyard/components/processors/video_embed_processor.rb +196 -0
- data/lib/docyard/components/support/code_group/html_builder.rb +122 -0
- data/lib/docyard/components/support/markdown_code_block_helper.rb +56 -0
- data/lib/docyard/config/branding_resolver.rb +121 -17
- data/lib/docyard/config/constants.rb +6 -4
- data/lib/docyard/config/logo_detector.rb +39 -0
- data/lib/docyard/config/validator.rb +122 -99
- data/lib/docyard/config.rb +40 -42
- data/lib/docyard/initializer.rb +15 -76
- data/lib/docyard/navigation/breadcrumb_builder.rb +133 -0
- data/lib/docyard/navigation/prev_next_builder.rb +4 -1
- data/lib/docyard/navigation/sidebar/children_discoverer.rb +51 -0
- data/lib/docyard/navigation/sidebar/config_parser.rb +136 -108
- data/lib/docyard/navigation/sidebar/file_resolver.rb +90 -0
- data/lib/docyard/navigation/sidebar/file_system_scanner.rb +2 -1
- data/lib/docyard/navigation/sidebar/item.rb +50 -7
- data/lib/docyard/navigation/sidebar/local_config_loader.rb +51 -0
- data/lib/docyard/navigation/sidebar/metadata_extractor.rb +71 -0
- data/lib/docyard/navigation/sidebar/metadata_reader.rb +51 -0
- data/lib/docyard/navigation/sidebar/path_prefixer.rb +34 -0
- data/lib/docyard/navigation/sidebar/renderer.rb +60 -38
- data/lib/docyard/navigation/sidebar/sorter.rb +21 -0
- data/lib/docyard/navigation/sidebar/tree_builder.rb +100 -26
- data/lib/docyard/navigation/sidebar/tree_filter.rb +55 -0
- data/lib/docyard/navigation/sidebar_builder.rb +105 -36
- data/lib/docyard/rendering/icon_helpers.rb +13 -0
- data/lib/docyard/rendering/icons/phosphor.rb +26 -1
- data/lib/docyard/rendering/markdown.rb +29 -1
- data/lib/docyard/rendering/renderer.rb +75 -34
- 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 +1 -1
- data/lib/docyard/search/dev_indexer.rb +51 -6
- data/lib/docyard/search/pagefind_support.rb +2 -0
- data/lib/docyard/server/asset_handler.rb +25 -19
- data/lib/docyard/server/pagefind_handler.rb +63 -0
- data/lib/docyard/server/preview_server.rb +1 -1
- data/lib/docyard/server/rack_application.rb +81 -64
- data/lib/docyard/templates/assets/css/code.css +18 -51
- data/lib/docyard/templates/assets/css/components/abbreviation.css +86 -0
- data/lib/docyard/templates/assets/css/components/accordion.css +138 -0
- data/lib/docyard/templates/assets/css/components/badges.css +47 -0
- data/lib/docyard/templates/assets/css/components/banner.css +202 -0
- 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/cards.css +100 -0
- data/lib/docyard/templates/assets/css/components/code-block.css +190 -282
- data/lib/docyard/templates/assets/css/components/code-group.css +281 -0
- data/lib/docyard/templates/assets/css/components/figure.css +22 -0
- data/lib/docyard/templates/assets/css/components/file-tree.css +124 -0
- data/lib/docyard/templates/assets/css/components/heading-anchor.css +36 -15
- data/lib/docyard/templates/assets/css/components/icon.css +0 -1
- data/lib/docyard/templates/assets/css/components/lightbox.css +65 -0
- 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 +193 -167
- data/lib/docyard/templates/assets/css/components/prev-next.css +68 -48
- data/lib/docyard/templates/assets/css/components/search.css +186 -174
- data/lib/docyard/templates/assets/css/components/steps.css +122 -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/components/tooltip.css +113 -0
- data/lib/docyard/templates/assets/css/components/video.css +41 -0
- data/lib/docyard/templates/assets/css/landing.css +815 -0
- data/lib/docyard/templates/assets/css/layout.css +489 -87
- data/lib/docyard/templates/assets/css/main.css +1 -3
- data/lib/docyard/templates/assets/css/markdown.css +113 -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/abbreviation.js +85 -0
- data/lib/docyard/templates/assets/js/components/banner.js +81 -0
- data/lib/docyard/templates/assets/js/components/code-block.js +24 -42
- data/lib/docyard/templates/assets/js/components/code-group.js +283 -0
- data/lib/docyard/templates/assets/js/components/file-tree.js +39 -0
- data/lib/docyard/templates/assets/js/components/heading-anchor.js +26 -24
- data/lib/docyard/templates/assets/js/components/lightbox.js +72 -0
- data/lib/docyard/templates/assets/js/components/navigation.js +181 -70
- data/lib/docyard/templates/assets/js/components/search.js +0 -75
- 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/components/tooltip.js +118 -0
- 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 -67
- data/lib/docyard/templates/layouts/splash.html.erb +177 -0
- data/lib/docyard/templates/partials/_accordion.html.erb +9 -0
- data/lib/docyard/templates/partials/_banner.html.erb +27 -0
- data/lib/docyard/templates/partials/_breadcrumbs.html.erb +24 -0
- data/lib/docyard/templates/partials/_card.html.erb +23 -0
- data/lib/docyard/templates/partials/_code_block.html.erb +5 -3
- 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 +31 -11
- data/lib/docyard/templates/partials/_nav_leaf.html.erb +4 -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 +8 -2
- data/lib/docyard/templates/partials/_scripts.html.erb +7 -0
- data/lib/docyard/templates/partials/_search_modal.html.erb +2 -6
- data/lib/docyard/templates/partials/_search_trigger.html.erb +2 -6
- data/lib/docyard/templates/partials/_sidebar.html.erb +21 -4
- data/lib/docyard/templates/partials/_step.html.erb +14 -0
- 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/version.rb +1 -1
- metadata +70 -5
- 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
|
@@ -9,21 +9,22 @@ module Docyard
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def validate!
|
|
12
|
-
|
|
12
|
+
validate_top_level
|
|
13
13
|
validate_branding_section
|
|
14
|
+
validate_socials_section
|
|
15
|
+
validate_tabs_section
|
|
14
16
|
validate_build_section
|
|
15
|
-
|
|
17
|
+
validate_search_section
|
|
18
|
+
validate_navigation_section
|
|
16
19
|
|
|
17
20
|
raise ConfigError, format_errors if @errors.any?
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
private
|
|
21
24
|
|
|
22
|
-
def
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
validate_string(site["title"], "site.title")
|
|
26
|
-
validate_string(site["description"], "site.description")
|
|
25
|
+
def validate_top_level
|
|
26
|
+
validate_string(@config["title"], "title")
|
|
27
|
+
validate_string(@config["description"], "description")
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def validate_branding_section
|
|
@@ -31,127 +32,141 @@ module Docyard
|
|
|
31
32
|
return unless branding
|
|
32
33
|
|
|
33
34
|
validate_file_path_or_url(branding["logo"], "branding.logo")
|
|
34
|
-
validate_file_path_or_url(branding["logo_dark"], "branding.logo_dark")
|
|
35
35
|
validate_file_path_or_url(branding["favicon"], "branding.favicon")
|
|
36
|
+
validate_boolean(branding["credits"], "branding.credits") if branding.key?("credits")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def validate_socials_section
|
|
40
|
+
socials = @config["socials"]
|
|
41
|
+
return unless socials
|
|
42
|
+
return add_hash_error("socials") unless socials.is_a?(Hash)
|
|
43
|
+
|
|
44
|
+
socials.each { |platform, url| validate_url(url, "socials.#{platform}") unless platform == "custom" }
|
|
45
|
+
validate_custom_socials(socials["custom"]) if socials.key?("custom")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def validate_custom_socials(custom)
|
|
49
|
+
return if custom.nil?
|
|
50
|
+
return add_array_error("socials.custom") unless custom.is_a?(Array)
|
|
36
51
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
52
|
+
custom.each_with_index do |item, index|
|
|
53
|
+
validate_string(item["icon"], "socials.custom[#{index}].icon")
|
|
54
|
+
validate_url(item["href"], "socials.custom[#{index}].href")
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def validate_tabs_section
|
|
59
|
+
tabs = @config["tabs"]
|
|
60
|
+
return unless tabs
|
|
61
|
+
return add_array_error("tabs") unless tabs.is_a?(Array)
|
|
62
|
+
|
|
63
|
+
tabs.each_with_index do |tab, index|
|
|
64
|
+
validate_string(tab["text"], "tabs[#{index}].text")
|
|
65
|
+
validate_string(tab["href"], "tabs[#{index}].href")
|
|
66
|
+
validate_boolean(tab["external"], "tabs[#{index}].external") if tab.key?("external")
|
|
67
|
+
end
|
|
40
68
|
end
|
|
41
69
|
|
|
42
70
|
def validate_build_section
|
|
43
71
|
build = @config["build"]
|
|
72
|
+
return unless build
|
|
44
73
|
|
|
45
|
-
validate_string(build["
|
|
46
|
-
validate_no_slashes(build["
|
|
47
|
-
validate_string(build["
|
|
48
|
-
validate_starts_with_slash(build["
|
|
49
|
-
validate_boolean(build["clean"], "build.clean")
|
|
74
|
+
validate_string(build["output"], "build.output")
|
|
75
|
+
validate_no_slashes(build["output"], "build.output")
|
|
76
|
+
validate_string(build["base"], "build.base")
|
|
77
|
+
validate_starts_with_slash(build["base"], "build.base")
|
|
50
78
|
end
|
|
51
79
|
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
return unless
|
|
80
|
+
def validate_search_section
|
|
81
|
+
search = @config["search"]
|
|
82
|
+
return unless search
|
|
55
83
|
|
|
56
|
-
validate_boolean(
|
|
84
|
+
validate_boolean(search["enabled"], "search.enabled") if search.key?("enabled")
|
|
85
|
+
validate_string(search["placeholder"], "search.placeholder") if search.key?("placeholder")
|
|
86
|
+
validate_array(search["exclude"], "search.exclude") if search.key?("exclude")
|
|
57
87
|
end
|
|
58
88
|
|
|
59
|
-
def
|
|
60
|
-
|
|
61
|
-
return if
|
|
89
|
+
def validate_navigation_section
|
|
90
|
+
cta = @config.dig("navigation", "cta")
|
|
91
|
+
return if cta.nil?
|
|
92
|
+
return add_array_error("navigation.cta") unless cta.is_a?(Array)
|
|
62
93
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
error: "must be a string",
|
|
66
|
-
got: value.class.name,
|
|
67
|
-
fix: "Change to a string value"
|
|
68
|
-
)
|
|
94
|
+
validate_cta_max_count(cta)
|
|
95
|
+
validate_cta_items(cta)
|
|
69
96
|
end
|
|
70
97
|
|
|
71
|
-
def
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
fix: "Change to true or false"
|
|
79
|
-
)
|
|
98
|
+
def validate_cta_items(cta)
|
|
99
|
+
cta.each_with_index do |item, idx|
|
|
100
|
+
validate_string(item["text"], "navigation.cta[#{idx}].text")
|
|
101
|
+
validate_string(item["href"], "navigation.cta[#{idx}].href")
|
|
102
|
+
validate_cta_variant(item["variant"], idx) if item.key?("variant")
|
|
103
|
+
validate_boolean(item["external"], "navigation.cta[#{idx}].external") if item.key?("external")
|
|
104
|
+
end
|
|
80
105
|
end
|
|
81
106
|
|
|
82
|
-
def
|
|
83
|
-
return if
|
|
84
|
-
return add_file_path_type_error(value, field_name) unless value.is_a?(String)
|
|
107
|
+
def validate_cta_max_count(cta)
|
|
108
|
+
return if cta.length <= 2
|
|
85
109
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
File.join("docs", value)
|
|
90
|
-
end
|
|
110
|
+
add_error(field: "navigation.cta", error: "maximum 2 CTAs allowed",
|
|
111
|
+
got: "#{cta.length} items", fix: "Remove extra CTA items to have at most 2")
|
|
112
|
+
end
|
|
91
113
|
|
|
92
|
-
|
|
114
|
+
def validate_cta_variant(variant, idx)
|
|
115
|
+
return if variant.nil? || %w[primary secondary].include?(variant)
|
|
93
116
|
|
|
94
|
-
|
|
117
|
+
add_error(field: "navigation.cta[#{idx}].variant", error: "must be 'primary' or 'secondary'",
|
|
118
|
+
got: variant, fix: "Change to 'primary' or 'secondary'")
|
|
95
119
|
end
|
|
96
120
|
|
|
97
|
-
def
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
got: value.class.name,
|
|
102
|
-
fix: "Change to a string file path"
|
|
103
|
-
)
|
|
121
|
+
def validate_string(value, field_name)
|
|
122
|
+
return if value.nil? || value.is_a?(String)
|
|
123
|
+
|
|
124
|
+
add_error(field: field_name, error: "must be a string", got: value.class.name, fix: "Change to a string value")
|
|
104
125
|
end
|
|
105
126
|
|
|
106
|
-
def
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
got: value,
|
|
111
|
-
fix: "Place the file in docs/ directory and use a relative path (e.g., 'assets/logo.svg')"
|
|
112
|
-
)
|
|
127
|
+
def validate_boolean(value, field_name)
|
|
128
|
+
return if [true, false].include?(value)
|
|
129
|
+
|
|
130
|
+
add_error(field: field_name, error: "must be true or false", got: value.inspect, fix: "Change to true or false")
|
|
113
131
|
end
|
|
114
132
|
|
|
115
|
-
def
|
|
116
|
-
return if value.nil?
|
|
117
|
-
return unless value.is_a?(String)
|
|
118
|
-
return unless value.include?("/") || value.include?("\\")
|
|
133
|
+
def validate_url(value, field_name)
|
|
134
|
+
return if value.nil? || value.is_a?(String)
|
|
119
135
|
|
|
120
|
-
add_error(
|
|
121
|
-
|
|
122
|
-
error: "cannot contain slashes",
|
|
123
|
-
got: value,
|
|
124
|
-
fix: "Use a simple directory name like 'dist' or '_site'"
|
|
125
|
-
)
|
|
136
|
+
add_error(field: field_name, error: "must be a URL string",
|
|
137
|
+
got: value.class.name, fix: "Change to a URL string")
|
|
126
138
|
end
|
|
127
139
|
|
|
128
|
-
def
|
|
129
|
-
return if value.nil?
|
|
130
|
-
return if value.start_with?("/")
|
|
140
|
+
def validate_array(value, field_name)
|
|
141
|
+
return if value.nil? || value.is_a?(Array)
|
|
131
142
|
|
|
132
|
-
|
|
133
|
-
field: field_name,
|
|
134
|
-
error: "must start with /",
|
|
135
|
-
got: value,
|
|
136
|
-
fix: "Change to '/#{value}'"
|
|
137
|
-
)
|
|
143
|
+
add_array_error(field_name)
|
|
138
144
|
end
|
|
139
145
|
|
|
140
146
|
def validate_file_path_or_url(value, field_name)
|
|
141
147
|
return if value.nil?
|
|
142
|
-
return
|
|
143
|
-
|
|
148
|
+
return add_type_error(field_name, "file path or URL (string)", value.class.name) unless value.is_a?(String)
|
|
144
149
|
return if url?(value)
|
|
145
150
|
|
|
146
|
-
file_path =
|
|
147
|
-
value
|
|
148
|
-
else
|
|
149
|
-
File.join("docs", value)
|
|
150
|
-
end
|
|
151
|
-
|
|
151
|
+
file_path = File.absolute_path?(value) ? value : File.join("docs/public", value)
|
|
152
152
|
return if File.exist?(file_path)
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
add_error(field: field_name, error: "file not found", got: value,
|
|
155
|
+
fix: "Place the file in docs/public/ directory (e.g., 'logo.svg' for docs/public/logo.svg)")
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def validate_no_slashes(value, field_name)
|
|
159
|
+
return if value.nil? || !value.is_a?(String)
|
|
160
|
+
return unless value.include?("/") || value.include?("\\")
|
|
161
|
+
|
|
162
|
+
add_error(field: field_name, error: "cannot contain slashes", got: value,
|
|
163
|
+
fix: "Use a simple directory name like 'dist' or '_site'")
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def validate_starts_with_slash(value, field_name)
|
|
167
|
+
return if value.nil? || value.start_with?("/")
|
|
168
|
+
|
|
169
|
+
add_error(field: field_name, error: "must start with /", got: value, fix: "Change to '/#{value}'")
|
|
155
170
|
end
|
|
156
171
|
|
|
157
172
|
def url?(value)
|
|
@@ -162,17 +177,25 @@ module Docyard
|
|
|
162
177
|
@errors << error_data
|
|
163
178
|
end
|
|
164
179
|
|
|
165
|
-
def
|
|
166
|
-
|
|
180
|
+
def add_type_error(field, expected, got)
|
|
181
|
+
add_error(field: field, error: "must be a #{expected}", got: got, fix: "Change to a #{expected}")
|
|
182
|
+
end
|
|
167
183
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
message += " Fix: #{err[:fix]}\n\n"
|
|
173
|
-
end
|
|
184
|
+
def add_hash_error(field)
|
|
185
|
+
add_error(field: field, error: "must be a hash", got: @config[field].class.name,
|
|
186
|
+
fix: "Change to a hash with platform names as keys and URLs as values")
|
|
187
|
+
end
|
|
174
188
|
|
|
175
|
-
|
|
189
|
+
def add_array_error(field)
|
|
190
|
+
value = field.split(".").reduce(@config) { |h, k| h&.[](k) }
|
|
191
|
+
add_error(field: field, error: "must be an array", got: value.class.name, fix: "Change to an array")
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def format_errors
|
|
195
|
+
errors_text = @errors.map do |err|
|
|
196
|
+
" Field: #{err[:field]}\n Error: #{err[:error]}\n Got: #{err[:got]}\n Fix: #{err[:fix]}"
|
|
197
|
+
end.join("\n\n")
|
|
198
|
+
"Error in docyard.yml:\n\n#{errors_text}"
|
|
176
199
|
end
|
|
177
200
|
end
|
|
178
201
|
end
|
data/lib/docyard/config.rb
CHANGED
|
@@ -7,42 +7,30 @@ require_relative "config/constants"
|
|
|
7
7
|
module Docyard
|
|
8
8
|
class Config
|
|
9
9
|
DEFAULT_CONFIG = {
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
"description" => ""
|
|
13
|
-
},
|
|
10
|
+
"title" => Constants::DEFAULT_SITE_TITLE,
|
|
11
|
+
"description" => "",
|
|
14
12
|
"branding" => {
|
|
15
13
|
"logo" => nil,
|
|
16
|
-
"logo_dark" => nil,
|
|
17
14
|
"favicon" => nil,
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
"title" => true
|
|
21
|
-
}
|
|
15
|
+
"credits" => true,
|
|
16
|
+
"copyright" => nil
|
|
22
17
|
},
|
|
18
|
+
"socials" => {},
|
|
19
|
+
"tabs" => [],
|
|
23
20
|
"build" => {
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"clean" => true
|
|
27
|
-
},
|
|
28
|
-
"sidebar" => {
|
|
29
|
-
"items" => []
|
|
30
|
-
},
|
|
31
|
-
"navigation" => {
|
|
32
|
-
"footer" => {
|
|
33
|
-
"enabled" => true,
|
|
34
|
-
"prev_text" => "Previous",
|
|
35
|
-
"next_text" => "Next"
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
"markdown" => {
|
|
39
|
-
"lineNumbers" => false
|
|
21
|
+
"output" => "dist",
|
|
22
|
+
"base" => "/"
|
|
40
23
|
},
|
|
41
24
|
"search" => {
|
|
42
25
|
"enabled" => true,
|
|
43
|
-
"placeholder" => "Search
|
|
26
|
+
"placeholder" => "Search...",
|
|
44
27
|
"exclude" => []
|
|
45
|
-
}
|
|
28
|
+
},
|
|
29
|
+
"navigation" => {
|
|
30
|
+
"cta" => [],
|
|
31
|
+
"breadcrumbs" => true
|
|
32
|
+
},
|
|
33
|
+
"announcement" => nil
|
|
46
34
|
}.freeze
|
|
47
35
|
|
|
48
36
|
attr_reader :data, :file_path
|
|
@@ -62,32 +50,40 @@ module Docyard
|
|
|
62
50
|
File.exist?(file_path)
|
|
63
51
|
end
|
|
64
52
|
|
|
65
|
-
def
|
|
66
|
-
|
|
53
|
+
def title
|
|
54
|
+
data["title"]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def description
|
|
58
|
+
data["description"]
|
|
67
59
|
end
|
|
68
60
|
|
|
69
61
|
def branding
|
|
70
62
|
@branding ||= ConfigSection.new(data["branding"])
|
|
71
63
|
end
|
|
72
64
|
|
|
65
|
+
def socials
|
|
66
|
+
data["socials"]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def tabs
|
|
70
|
+
data["tabs"]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
73
|
def build
|
|
74
74
|
@build ||= ConfigSection.new(data["build"])
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
def
|
|
78
|
-
@
|
|
77
|
+
def search
|
|
78
|
+
@search ||= ConfigSection.new(data["search"])
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
def navigation
|
|
82
82
|
@navigation ||= ConfigSection.new(data["navigation"])
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
def
|
|
86
|
-
@
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def search
|
|
90
|
-
@search ||= ConfigSection.new(data["search"])
|
|
85
|
+
def announcement
|
|
86
|
+
@announcement ||= data["announcement"] ? ConfigSection.new(data["announcement"]) : nil
|
|
91
87
|
end
|
|
92
88
|
|
|
93
89
|
private
|
|
@@ -122,7 +118,13 @@ module Docyard
|
|
|
122
118
|
end
|
|
123
119
|
|
|
124
120
|
def deep_dup(hash)
|
|
125
|
-
hash.transform_values
|
|
121
|
+
hash.transform_values do |value|
|
|
122
|
+
case value
|
|
123
|
+
when Hash then deep_dup(value)
|
|
124
|
+
when Array then value.map { |v| v.is_a?(Hash) ? deep_dup(v) : v }
|
|
125
|
+
else value
|
|
126
|
+
end
|
|
127
|
+
end
|
|
126
128
|
end
|
|
127
129
|
|
|
128
130
|
def build_yaml_error_message(error)
|
|
@@ -143,10 +145,6 @@ module Docyard
|
|
|
143
145
|
@data = data || {}
|
|
144
146
|
end
|
|
145
147
|
|
|
146
|
-
def appearance
|
|
147
|
-
@data["appearance"]
|
|
148
|
-
end
|
|
149
|
-
|
|
150
148
|
def method_missing(method, *args)
|
|
151
149
|
return @data[method.to_s] if args.empty?
|
|
152
150
|
|
data/lib/docyard/initializer.rb
CHANGED
|
@@ -5,16 +5,8 @@ require "fileutils"
|
|
|
5
5
|
module Docyard
|
|
6
6
|
class Initializer
|
|
7
7
|
DOCS_DIR = "docs"
|
|
8
|
-
TEMPLATE_DIR = File.join(__dir__, "templates", "markdown")
|
|
9
8
|
CONFIG_TEMPLATE_DIR = File.join(__dir__, "templates", "config")
|
|
10
9
|
|
|
11
|
-
TEMPLATES = {
|
|
12
|
-
"index.md" => "index.md.erb",
|
|
13
|
-
"getting-started/installation.md" => "getting-started/installation.md.erb",
|
|
14
|
-
"guides/markdown-features.md" => "guides/markdown-features.md.erb",
|
|
15
|
-
"guides/configuration.md" => "guides/configuration.md.erb"
|
|
16
|
-
}.freeze
|
|
17
|
-
|
|
18
10
|
def initialize(path = ".")
|
|
19
11
|
@path = path
|
|
20
12
|
@docs_path = File.join(@path, DOCS_DIR)
|
|
@@ -39,23 +31,22 @@ module Docyard
|
|
|
39
31
|
|
|
40
32
|
def create_structure
|
|
41
33
|
FileUtils.mkdir_p(@docs_path)
|
|
42
|
-
|
|
43
|
-
TEMPLATES.each do |output_name, template_name|
|
|
44
|
-
copy_template(template_name, output_name)
|
|
45
|
-
end
|
|
46
|
-
|
|
34
|
+
create_index_file
|
|
47
35
|
create_example_config
|
|
48
36
|
end
|
|
49
37
|
|
|
50
|
-
def
|
|
51
|
-
|
|
52
|
-
|
|
38
|
+
def create_index_file
|
|
39
|
+
index_path = File.join(@docs_path, "index.md")
|
|
40
|
+
content = <<~MARKDOWN
|
|
41
|
+
---
|
|
42
|
+
title: Welcome
|
|
43
|
+
---
|
|
53
44
|
|
|
54
|
-
|
|
55
|
-
FileUtils.mkdir_p(output_dir) unless File.directory?(output_dir)
|
|
45
|
+
# Welcome to Your Documentation
|
|
56
46
|
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
Start writing your documentation here.
|
|
48
|
+
MARKDOWN
|
|
49
|
+
File.write(index_path, content)
|
|
59
50
|
end
|
|
60
51
|
|
|
61
52
|
def create_example_config
|
|
@@ -81,16 +72,16 @@ module Docyard
|
|
|
81
72
|
|
|
82
73
|
def print_banner
|
|
83
74
|
puts ""
|
|
84
|
-
puts "
|
|
85
|
-
puts "│ ✓ Docyard initialized successfully │"
|
|
86
|
-
puts "└─────────────────────────────────────────────────────────────┘"
|
|
75
|
+
puts "Docyard initialized successfully"
|
|
87
76
|
puts ""
|
|
88
77
|
end
|
|
89
78
|
|
|
90
79
|
def print_created_files
|
|
91
80
|
puts "Created files:"
|
|
92
81
|
puts ""
|
|
93
|
-
|
|
82
|
+
puts " docs/"
|
|
83
|
+
puts " index.md"
|
|
84
|
+
puts " docyard.yml"
|
|
94
85
|
puts ""
|
|
95
86
|
end
|
|
96
87
|
|
|
@@ -99,62 +90,10 @@ module Docyard
|
|
|
99
90
|
puts ""
|
|
100
91
|
puts " Start development server:"
|
|
101
92
|
puts " docyard serve"
|
|
102
|
-
puts " → http://localhost:4200"
|
|
103
93
|
puts ""
|
|
104
94
|
puts " Build for production:"
|
|
105
95
|
puts " docyard build"
|
|
106
96
|
puts ""
|
|
107
|
-
puts " Preview production build:"
|
|
108
|
-
puts " docyard preview"
|
|
109
|
-
puts ""
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def print_file_tree
|
|
113
|
-
puts " ├── docs/"
|
|
114
|
-
|
|
115
|
-
grouped_files = TEMPLATES.keys.group_by { |file| File.dirname(file) }
|
|
116
|
-
sorted_dirs = grouped_files.keys.sort
|
|
117
|
-
|
|
118
|
-
sorted_dirs.each_with_index do |dir, dir_idx|
|
|
119
|
-
print_directory_group(dir, grouped_files[dir], dir_idx == sorted_dirs.length - 1)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
puts " └── docyard.yml"
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def print_directory_group(dir, files, is_last_dir)
|
|
126
|
-
sorted_files = files.sort
|
|
127
|
-
|
|
128
|
-
if dir == "."
|
|
129
|
-
print_root_files(sorted_files, is_last_dir)
|
|
130
|
-
else
|
|
131
|
-
print_subdirectory(dir, sorted_files, is_last_dir)
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def print_root_files(files, is_last_dir)
|
|
136
|
-
files.each_with_index do |file, idx|
|
|
137
|
-
is_last = idx == files.length - 1 && is_last_dir
|
|
138
|
-
prefix = is_last ? " │ └──" : " │ ├──"
|
|
139
|
-
puts "#{prefix} #{file}"
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def print_subdirectory(dir, files, is_last_dir)
|
|
144
|
-
dir_prefix = is_last_dir ? " │ └──" : " │ ├──"
|
|
145
|
-
puts "#{dir_prefix} #{dir}/"
|
|
146
|
-
|
|
147
|
-
files.each_with_index do |file, idx|
|
|
148
|
-
print_subdirectory_file(file, idx, files.length, is_last_dir)
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def print_subdirectory_file(file, idx, total, is_last_dir)
|
|
153
|
-
is_last_file = idx == total - 1
|
|
154
|
-
file_prefix = is_last_dir ? " │ " : " │ │ "
|
|
155
|
-
file_prefix += is_last_file ? "└──" : "├──"
|
|
156
|
-
basename = File.basename(file)
|
|
157
|
-
puts "#{file_prefix} #{basename}"
|
|
158
97
|
end
|
|
159
98
|
end
|
|
160
99
|
end
|