docyard 0.2.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 +42 -1
- data/LICENSE.vscode-icons +42 -0
- data/README.md +86 -23
- data/lib/docyard/asset_handler.rb +33 -0
- data/lib/docyard/build/asset_bundler.rb +139 -0
- data/lib/docyard/build/file_copier.rb +105 -0
- data/lib/docyard/build/sitemap_generator.rb +57 -0
- data/lib/docyard/build/static_generator.rb +141 -0
- data/lib/docyard/builder.rb +104 -0
- data/lib/docyard/cli.rb +19 -0
- data/lib/docyard/components/base_processor.rb +24 -0
- data/lib/docyard/components/callout_processor.rb +121 -0
- data/lib/docyard/components/code_block_processor.rb +55 -0
- data/lib/docyard/components/code_detector.rb +59 -0
- data/lib/docyard/components/icon_detector.rb +57 -0
- data/lib/docyard/components/icon_processor.rb +51 -0
- data/lib/docyard/components/registry.rb +34 -0
- data/lib/docyard/components/table_wrapper_processor.rb +18 -0
- data/lib/docyard/components/tabs_parser.rb +60 -0
- data/lib/docyard/components/tabs_processor.rb +44 -0
- data/lib/docyard/config/validator.rb +171 -0
- data/lib/docyard/config.rb +135 -0
- data/lib/docyard/constants.rb +5 -0
- data/lib/docyard/icons/LICENSE.phosphor +21 -0
- data/lib/docyard/icons/file_types.rb +92 -0
- data/lib/docyard/icons/phosphor.rb +64 -0
- data/lib/docyard/icons.rb +40 -0
- data/lib/docyard/initializer.rb +93 -9
- data/lib/docyard/language_mapping.rb +52 -0
- data/lib/docyard/markdown.rb +27 -3
- data/lib/docyard/preview_server.rb +72 -0
- data/lib/docyard/rack_application.rb +77 -8
- data/lib/docyard/renderer.rb +56 -9
- data/lib/docyard/server.rb +5 -2
- data/lib/docyard/sidebar/config_parser.rb +180 -0
- data/lib/docyard/sidebar/item.rb +58 -0
- data/lib/docyard/sidebar/renderer.rb +33 -6
- data/lib/docyard/sidebar_builder.rb +54 -2
- data/lib/docyard/templates/assets/css/code.css +150 -2
- data/lib/docyard/templates/assets/css/components/callout.css +169 -0
- data/lib/docyard/templates/assets/css/components/code-block.css +196 -0
- data/lib/docyard/templates/assets/css/components/icon.css +16 -0
- data/lib/docyard/templates/assets/css/components/logo.css +44 -0
- data/lib/docyard/templates/assets/css/{components.css → components/navigation.css} +111 -53
- data/lib/docyard/templates/assets/css/components/tabs.css +299 -0
- data/lib/docyard/templates/assets/css/components/theme-toggle.css +69 -0
- data/lib/docyard/templates/assets/css/layout.css +14 -4
- data/lib/docyard/templates/assets/css/markdown.css +27 -17
- data/lib/docyard/templates/assets/css/reset.css +4 -0
- data/lib/docyard/templates/assets/css/variables.css +94 -3
- data/lib/docyard/templates/assets/favicon.svg +16 -0
- data/lib/docyard/templates/assets/js/components/code-block.js +162 -0
- data/lib/docyard/templates/assets/js/components/navigation.js +221 -0
- data/lib/docyard/templates/assets/js/components/tabs.js +338 -0
- data/lib/docyard/templates/assets/js/theme.js +12 -179
- data/lib/docyard/templates/assets/logo-dark.svg +4 -0
- data/lib/docyard/templates/assets/logo.svg +12 -0
- data/lib/docyard/templates/config/docyard.yml.erb +42 -0
- data/lib/docyard/templates/layouts/default.html.erb +32 -4
- data/lib/docyard/templates/markdown/getting-started/installation.md.erb +46 -12
- data/lib/docyard/templates/markdown/guides/configuration.md.erb +202 -0
- data/lib/docyard/templates/markdown/guides/markdown-features.md.erb +247 -0
- data/lib/docyard/templates/markdown/index.md.erb +55 -59
- data/lib/docyard/templates/partials/_callout.html.erb +11 -0
- data/lib/docyard/templates/partials/_code_block.html.erb +6 -0
- data/lib/docyard/templates/partials/_icon.html.erb +1 -0
- data/lib/docyard/templates/partials/_icon_file_extension.html.erb +1 -0
- data/lib/docyard/templates/partials/_nav_group.html.erb +10 -4
- data/lib/docyard/templates/partials/_nav_leaf.html.erb +9 -1
- data/lib/docyard/templates/partials/_tabs.html.erb +40 -0
- data/lib/docyard/templates/partials/_theme_toggle.html.erb +13 -0
- data/lib/docyard/version.rb +1 -1
- data/lib/docyard.rb +8 -0
- metadata +91 -7
- data/lib/docyard/templates/markdown/core-concepts/file-structure.md.erb +0 -61
- data/lib/docyard/templates/markdown/core-concepts/markdown.md.erb +0 -90
- data/lib/docyard/templates/markdown/getting-started/introduction.md.erb +0 -30
- data/lib/docyard/templates/markdown/getting-started/quick-start.md.erb +0 -56
- data/lib/docyard/templates/partials/_icons.html.erb +0 -11
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Layout/LineLength
|
|
4
|
+
module Docyard
|
|
5
|
+
module Icons
|
|
6
|
+
# Phosphor Icons - https://phosphoricons.com
|
|
7
|
+
# Copyright (c) 2020-2023 Phosphor Icons
|
|
8
|
+
# Licensed under MIT License (see LICENSE.phosphor)
|
|
9
|
+
PHOSPHOR = {
|
|
10
|
+
"regular" => {
|
|
11
|
+
"heart" => '<path d="M178,40c-20.65,0-38.73,8.88-50,23.89C116.73,48.88,98.65,40,78,40a62.07,62.07,0,0,0-62,62c0,70,103.79,126.66,108.21,129a8,8,0,0,0,7.58,0C136.21,228.66,240,172,240,102A62.07,62.07,0,0,0,178,40ZM128,214.8C109.74,204.16,32,155.69,32,102A46.06,46.06,0,0,1,78,56c19.45,0,35.78,10.36,42.6,27a8,8,0,0,0,14.8,0c6.82-16.67,23.15-27,42.6-27a46.06,46.06,0,0,1,46,46C224,155.61,146.24,204.15,128,214.8Z"/>',
|
|
12
|
+
"arrow-right" => '<path d="M221.66,133.66l-72,72a8,8,0,0,1-11.32-11.32L196.69,136H40a8,8,0,0,1,0-16H196.69L138.34,61.66a8,8,0,0,1,11.32-11.32l72,72A8,8,0,0,1,221.66,133.66Z"/>',
|
|
13
|
+
"arrow-left" => '<path d="M224,128a8,8,0,0,1-8,8H59.31l58.35,58.34a8,8,0,0,1-11.32,11.32l-72-72a8,8,0,0,1,0-11.32l72-72a8,8,0,0,1,11.32,11.32L59.31,120H216A8,8,0,0,1,224,128Z"/>',
|
|
14
|
+
"arrow-up" => '<path d="M205.66,117.66a8,8,0,0,1-11.32,0L136,59.31V216a8,8,0,0,1-16,0V59.31L61.66,117.66a8,8,0,0,1-11.32-11.32l72-72a8,8,0,0,1,11.32,0l72,72A8,8,0,0,1,205.66,117.66Z"/>',
|
|
15
|
+
"arrow-down" => '<path d="M205.66,149.66l-72,72a8,8,0,0,1-11.32,0l-72-72a8,8,0,0,1,11.32-11.32L120,196.69V40a8,8,0,0,1,16,0V196.69l58.34-58.35a8,8,0,0,1,11.32,11.32Z"/>',
|
|
16
|
+
"check" => '<path d="M229.66,77.66l-128,128a8,8,0,0,1-11.32,0l-56-56a8,8,0,0,1,11.32-11.32L96,188.69,218.34,66.34a8,8,0,0,1,11.32,11.32Z"/>',
|
|
17
|
+
"x" => '<path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"/>',
|
|
18
|
+
"warning" => '<path d="M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z"/>',
|
|
19
|
+
"info" => '<path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm16-40a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176ZM112,84a12,12,0,1,1,12,12A12,12,0,0,1,112,84Z"/>',
|
|
20
|
+
"code" => '<path d="M69.12,94.15,28.5,128l40.62,33.85a8,8,0,1,1-10.24,12.29l-48-40a8,8,0,0,1,0-12.29l48-40a8,8,0,0,1,10.24,12.3Zm176,27.7-48-40a8,8,0,1,0-10.24,12.3L227.5,128l-40.62,33.85a8,8,0,1,0,10.24,12.29l48-40a8,8,0,0,0,0-12.29ZM162.73,32.48a8,8,0,0,0-10.25,4.79l-64,176a8,8,0,0,0,4.79,10.26A8.14,8.14,0,0,0,96,224a8,8,0,0,0,7.52-5.27l64-176A8,8,0,0,0,162.73,32.48Z"/>',
|
|
21
|
+
"terminal" => '<path d="M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,160H40V56H216V200ZM117.31,134.17,93.65,152l23.66,17.82a8,8,0,1,1-9.63,12.79l-32-24a8,8,0,0,1,0-12.8l32-24a8,8,0,0,1,9.63,12.79ZM160,168H136a8,8,0,0,1,0-16h24a8,8,0,0,1,0,16Z"/>',
|
|
22
|
+
"package" => '<path d="M223.68,66.15,135.68,18a15.88,15.88,0,0,0-15.36,0l-88,48.17a16,16,0,0,0-8.32,14v95.64a16,16,0,0,0,8.32,14l88,48.17a15.88,15.88,0,0,0,15.36,0l88-48.17a16,16,0,0,0,8.32-14V80.18A16,16,0,0,0,223.68,66.15ZM128,32l80.34,44-29.77,16.3-80.35-44ZM128,120,47.66,76l33.9-18.56,80.34,44ZM40,90l80,43.78v85.79L40,175.82Zm176,85.78h0l-80,43.79V133.82l32-17.51V152a8,8,0,0,0,16,0V107.55L216,90v85.77Z"/>',
|
|
23
|
+
"rocket-launch" => '<path d="M223.85,47.12a16,16,0,0,0-15-15c-12.58-.75-44.73.4-71.41,27.07L132.69,64H74.36A15.91,15.91,0,0,0,63,68.68L28.7,103a16,16,0,0,0,9.07,27.16l38.47,5.37,44.21,44.21,5.37,38.49a15.94,15.94,0,0,0,10.78,12.92,16.11,16.11,0,0,0,5.1.83A15.91,15.91,0,0,0,153,227.3L187.32,193A15.91,15.91,0,0,0,192,181.64V123.31l4.77-4.77C223.45,91.86,224.6,59.71,223.85,47.12ZM74.36,80h42.33L77.16,119.52,40,114.34Zm74.41-9.45a76.65,76.65,0,0,1,59.11-22.47,76.46,76.46,0,0,1-22.42,59.16L128,164.68,91.32,128ZM176,181.64,141.67,216l-5.19-37.17L176,139.31Zm-74.16,9.5C97.34,201,82.29,224,40,224a8,8,0,0,1-8-8c0-42.29,23-57.34,32.86-61.85a8,8,0,0,1,6.64,14.56c-6.43,2.93-20.62,12.36-23.12,38.91,26.55-2.5,36-16.69,38.91-23.12a8,8,0,1,1,14.56,6.64Z"/>',
|
|
24
|
+
"star" => '<path d="M239.18,97.26A16.38,16.38,0,0,0,224.92,86l-59-4.76L143.14,26.15a16.36,16.36,0,0,0-30.27,0L90.11,81.23,31.08,86a16.46,16.46,0,0,0-9.37,28.86l45,38.83L53,211.75a16.38,16.38,0,0,0,24.5,17.82L128,198.49l50.53,31.08A16.4,16.4,0,0,0,203,211.75l-13.76-58.07,45-38.83A16.43,16.43,0,0,0,239.18,97.26Zm-15.34,5.47-48.7,42a8,8,0,0,0-2.56,7.91l14.88,62.8a.37.37,0,0,1-.17.48c-.18.14-.23.11-.38,0l-54.72-33.65a8,8,0,0,0-8.38,0L69.09,215.94c-.15.09-.19.12-.38,0a.37.37,0,0,1-.17-.48l14.88-62.8a8,8,0,0,0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16A8,8,0,0,0,103,91.86l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153,91.86a8,8,0,0,0,6.75,4.92l63.92,5.16c.15,0,.24,0,.33.29S224,102.63,223.84,102.73Z"/>',
|
|
25
|
+
"lightning" => '<path d="M215.79,118.17a8,8,0,0,0-5-5.66L153.18,90.9l14.66-73.33a8,8,0,0,0-13.69-7l-112,120a8,8,0,0,0,3,13l57.63,21.61L88.16,238.43a8,8,0,0,0,13.69,7l112-120A8,8,0,0,0,215.79,118.17ZM109.37,214l10.47-52.38a8,8,0,0,0-5-9.06L62,132.71l84.62-90.66L136.16,94.43a8,8,0,0,0,5,9.06l52.8,19.8Z"/>',
|
|
26
|
+
"moon-stars" => '<path d="M240,96a8,8,0,0,1-8,8H216v16a8,8,0,0,1-16,0V104H184a8,8,0,0,1,0-16h16V72a8,8,0,0,1,16,0V88h16A8,8,0,0,1,240,96ZM144,56h8v8a8,8,0,0,0,16,0V56h8a8,8,0,0,0,0-16h-8V32a8,8,0,0,0-16,0v8h-8a8,8,0,0,0,0,16Zm72.77,97a8,8,0,0,1,1.43,8A96,96,0,1,1,95.07,37.8a8,8,0,0,1,10.6,9.06A88.07,88.07,0,0,0,209.14,150.33,8,8,0,0,1,216.77,153Zm-19.39,14.88c-1.79.09-3.59.14-5.38.14A104.11,104.11,0,0,1,88,64c0-1.79,0-3.59.14-5.38A80,80,0,1,0,197.38,167.86Z"/>',
|
|
27
|
+
"sun" => '<path d="M120,40V16a8,8,0,0,1,16,0V40a8,8,0,0,1-16,0Zm72,88a64,64,0,1,1-64-64A64.07,64.07,0,0,1,192,128Zm-16,0a48,48,0,1,0-48,48A48.05,48.05,0,0,0,176,128ZM58.34,69.66A8,8,0,0,0,69.66,58.34l-16-16A8,8,0,0,0,42.34,53.66Zm0,116.68-16,16a8,8,0,0,0,11.32,11.32l16-16a8,8,0,0,0-11.32-11.32ZM192,72a8,8,0,0,0,5.66-2.34l16-16a8,8,0,0,0-11.32-11.32l-16,16A8,8,0,0,0,192,72Zm5.66,114.34a8,8,0,0,0-11.32,11.32l16,16a8,8,0,0,0,11.32-11.32ZM48,128a8,8,0,0,0-8-8H16a8,8,0,0,0,0,16H40A8,8,0,0,0,48,128Zm80,80a8,8,0,0,0-8,8v24a8,8,0,0,0,16,0V216A8,8,0,0,0,128,208Zm112-88H216a8,8,0,0,0,0,16h24a8,8,0,0,0,0-16Z"/>',
|
|
28
|
+
"link-external" => '<path d="M224,104a8,8,0,0,1-16,0V59.32l-66.33,66.34a8,8,0,0,1-11.32-11.32L196.68,48H152a8,8,0,0,1,0-16h64a8,8,0,0,1,8,8Zm-40,24a8,8,0,0,0-8,8v72H48V80h72a8,8,0,0,0,0-16H48A16,16,0,0,0,32,80V208a16,16,0,0,0,16,16H176a16,16,0,0,0,16-16V136A8,8,0,0,0,184,128Z"/>',
|
|
29
|
+
"copy" => '<path d="M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32ZM160,208H48V96H160Zm48-48H176V88a8,8,0,0,0-8-8H96V48H208Z"/>',
|
|
30
|
+
"caret-right" => '<path d="M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z"/>',
|
|
31
|
+
"github" => '<path d="M208.31,75.68A59.78,59.78,0,0,0,202.93,28,8,8,0,0,0,196,24a59.75,59.75,0,0,0-48,24H124A59.75,59.75,0,0,0,76,24a8,8,0,0,0-6.93,4,59.78,59.78,0,0,0-5.38,47.68A58.14,58.14,0,0,0,56,104v8a56.06,56.06,0,0,0,48.44,55.47A39.8,39.8,0,0,0,96,192v8H72a24,24,0,0,1-24-24A40,40,0,0,0,8,136a8,8,0,0,0,0,16,24,24,0,0,1,24,24,40,40,0,0,0,40,40H96v16a8,8,0,0,0,16,0V192a24,24,0,0,1,48,0v40a8,8,0,0,0,16,0V192a39.8,39.8,0,0,0-8.44-24.53A56.06,56.06,0,0,0,216,112v-8A58.14,58.14,0,0,0,208.31,75.68ZM200,112a40,40,0,0,1-40,40H112a40,40,0,0,1-40-40v-8a41.74,41.74,0,0,1,6.9-22.48,8,8,0,0,0,1.1-7.69,43.81,43.81,0,0,1,.79-33.58,43.88,43.88,0,0,1,32.32,20.06,8,8,0,0,0,6.71,3.69h32.35a8,8,0,0,0,6.74-3.69,43.87,43.87,0,0,1,32.32-20.06,43.81,43.81,0,0,1,.77,33.58,8.09,8.09,0,0,0,1,7.65,41.76,41.76,0,0,1,7,22.52Z"/>',
|
|
32
|
+
"question" => '<path d="M140,180a12,12,0,1,1-12-12A12,12,0,0,1,140,180ZM128,72c-22.06,0-40,16.15-40,36v4a8,8,0,0,0,16,0v-4c0-11,10.77-20,24-20s24,9,24,20-10.77,20-24,20a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-.72c18.24-3.35,32-17.9,32-35.28C168,88.15,150.06,72,128,72Zm104,56A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z"/>',
|
|
33
|
+
"lightbulb" => '<path d="M176,232a8,8,0,0,1-8,8H88a8,8,0,0,1,0-16h80A8,8,0,0,1,176,232Zm40-128a87.55,87.55,0,0,1-33.64,69.21A16.24,16.24,0,0,0,176,186v6a16,16,0,0,1-16,16H96a16,16,0,0,1-16-16v-6a16,16,0,0,0-6.23-12.66A87.59,87.59,0,0,1,40,104.49C39.74,56.83,78.26,17.14,125.88,16A88,88,0,0,1,216,104Zm-16,0a72,72,0,0,0-73.74-72c-39,.92-70.47,33.39-70.26,72.39a71.65,71.65,0,0,0,27.64,56.3A32,32,0,0,1,96,186v6h64v-6a32.15,32.15,0,0,1,12.47-25.35A71.65,71.65,0,0,0,200,104Zm-16.11-9.34a57.6,57.6,0,0,0-46.56-46.55,8,8,0,0,0-2.66,15.78c16.57,2.79,30.63,16.85,33.44,33.45A8,8,0,0,0,176,104a9,9,0,0,0,1.35-.11A8,8,0,0,0,183.89,94.66Z"/>',
|
|
34
|
+
"warning-circle" => '<path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z"/>',
|
|
35
|
+
"warning-octagon" => '<path d="M120,136V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0ZM232,91.55v72.9a15.86,15.86,0,0,1-4.69,11.31l-51.55,51.55A15.86,15.86,0,0,1,164.45,232H91.55a15.86,15.86,0,0,1-11.31-4.69L28.69,175.76A15.86,15.86,0,0,1,24,164.45V91.55a15.86,15.86,0,0,1,4.69-11.31L80.24,28.69A15.86,15.86,0,0,1,91.55,24h72.9a15.86,15.86,0,0,1,11.31,4.69l51.55,51.55A15.86,15.86,0,0,1,232,91.55Zm-16,0L164.45,40H91.55L40,91.55v72.9L91.55,216h72.9L216,164.45ZM128,160a12,12,0,1,0,12,12A12,12,0,0,0,128,160Z"/>',
|
|
36
|
+
"siren" => '<path d="M120,16V8a8,8,0,0,1,16,0v8a8,8,0,0,1-16,0Zm80,32a8,8,0,0,0,5.66-2.34l8-8a8,8,0,0,0-11.32-11.32l-8,8A8,8,0,0,0,200,48ZM50.34,45.66A8,8,0,0,0,61.66,34.34l-8-8A8,8,0,0,0,42.34,37.66Zm87,26.45a8,8,0,1,0-2.64,15.78C153.67,91.08,168,108.32,168,128a8,8,0,0,0,16,0C184,100.6,163.93,76.57,137.32,72.11ZM232,176v24a16,16,0,0,1-16,16H40a16,16,0,0,1-16-16V176a16,16,0,0,1,16-16V128a88,88,0,0,1,88.67-88c48.15.36,87.33,40.29,87.33,89v31A16,16,0,0,1,232,176ZM56,160H200V129c0-40-32.05-72.71-71.45-73H128a72,72,0,0,0-72,72Zm160,40V176H40v24H216Z"/>',
|
|
37
|
+
"file" => '<path d="M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160ZM200,216H56V40h88V88a8,8,0,0,0,8,8h48V216Z"/>',
|
|
38
|
+
"terminal-window" => '<path d="M128,128a8,8,0,0,1-3,6.25l-40,32a8,8,0,1,1-10-12.5L107.19,128,75,102.25a8,8,0,1,1,10-12.5l40,32A8,8,0,0,1,128,128Zm48,24H136a8,8,0,0,0,0,16h40a8,8,0,0,0,0-16Zm56-96V200a16,16,0,0,1-16,16H40a16,16,0,0,1-16-16V56A16,16,0,0,1,40,40H216A16,16,0,0,1,232,56ZM216,200V56H40V200H216Z"/>'
|
|
39
|
+
},
|
|
40
|
+
"bold" => {
|
|
41
|
+
"heart" => '<path d="M178,36c-20.09,0-37.92,7.93-50,21.56C115.92,43.93,98.09,36,78,36a66.08,66.08,0,0,0-66,66c0,72.34,105.81,130.14,110.31,132.57a12,12,0,0,0,11.38,0C138.19,232.14,244,174.34,244,102A66.08,66.08,0,0,0,178,36Zm-5.49,142.36A328.69,328.69,0,0,1,128,210.16a328.69,328.69,0,0,1-44.51-31.8C61.82,159.77,36,131.42,36,102A42,42,0,0,1,78,60c17.8,0,32.7,9.4,38.89,24.54a12,12,0,0,0,22.22,0C145.3,69.4,160.2,60,178,60a42,42,0,0,1,42,42C220,131.42,194.18,159.77,172.51,178.36Z"/>'
|
|
42
|
+
},
|
|
43
|
+
"fill" => {
|
|
44
|
+
"heart" => '<path d="M240,102c0,70-103.79,126.66-108.21,129a8,8,0,0,1-7.58,0C119.79,228.66,16,172,16,102A62.07,62.07,0,0,1,78,40c20.65,0,38.73,8.88,50,23.89C139.27,48.88,157.35,40,178,40A62.07,62.07,0,0,1,240,102Z"/>'
|
|
45
|
+
},
|
|
46
|
+
"light" => {
|
|
47
|
+
"heart" => '<path d="M178,42c-21,0-39.26,9.47-50,25.34C117.26,51.47,99,42,78,42a60.07,60.07,0,0,0-60,60c0,29.2,18.2,59.59,54.1,90.31a334.68,334.68,0,0,0,53.06,37,6,6,0,0,0,5.68,0,334.68,334.68,0,0,0,53.06-37C219.8,161.59,238,131.2,238,102A60.07,60.07,0,0,0,178,42ZM128,217.11C111.59,207.64,30,157.72,30,102A48.05,48.05,0,0,1,78,54c20.28,0,37.31,10.83,44.45,28.27a6,6,0,0,0,11.1,0C140.69,64.83,157.72,54,178,54a48.05,48.05,0,0,1,48,48C226,157.72,144.41,207.64,128,217.11Z"/>'
|
|
48
|
+
},
|
|
49
|
+
"thin" => {
|
|
50
|
+
"heart" => '<path d="M178,44c-21.44,0-39.92,10.19-50,27.07C117.92,54.19,99.44,44,78,44a58.07,58.07,0,0,0-58,58c0,28.59,18,58.47,53.4,88.79a333.81,333.81,0,0,0,52.7,36.73,4,4,0,0,0,3.8,0,333.81,333.81,0,0,0,52.7-36.73C218,160.47,236,130.59,236,102A58.07,58.07,0,0,0,178,44ZM128,219.42c-14-8-100-59.35-100-117.42A50.06,50.06,0,0,1,78,52c21.11,0,38.85,11.31,46.3,29.51a4,4,0,0,0,7.4,0C139.15,63.31,156.89,52,178,52a50.06,50.06,0,0,1,50,50C228,160,142,211.46,128,219.42Z"/>'
|
|
51
|
+
},
|
|
52
|
+
"duotone" => {
|
|
53
|
+
"heart" => '<path d="M232,102c0,66-104,122-104,122S24,168,24,102A54,54,0,0,1,78,48c22.59,0,41.94,12.31,50,32,8.06-19.69,27.41-32,50-32A54,54,0,0,1,232,102Z" opacity="0.2"/><path d="M178,40c-20.65,0-38.73,8.88-50,23.89C116.73,48.88,98.65,40,78,40a62.07,62.07,0,0,0-62,62c0,70,103.79,126.66,108.21,129a8,8,0,0,0,7.58,0C136.21,228.66,240,172,240,102A62.07,62.07,0,0,0,178,40ZM128,214.8C109.74,204.16,32,155.69,32,102A46.06,46.06,0,0,1,78,56c19.45,0,35.78,10.36,42.6,27a8,8,0,0,0,14.8,0c6.82-16.67,23.15-27,42.6-27a46.06,46.06,0,0,1,46,46C224,155.61,146.24,204.15,128,214.8Z"/>',
|
|
54
|
+
"info" => '<path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm16-40a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176ZM112,84a12,12,0,1,1,12,12A12,12,0,0,1,112,84Z"/>',
|
|
55
|
+
"warning" => '<path d="M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z"/>',
|
|
56
|
+
"lightbulb" => '<path d="M176,232a8,8,0,0,1-8,8H88a8,8,0,0,1,0-16h80A8,8,0,0,1,176,232Zm40-128a87.55,87.55,0,0,1-33.64,69.21A16.24,16.24,0,0,0,176,186v6a16,16,0,0,1-16,16H96a16,16,0,0,1-16-16v-6a16,16,0,0,0-6.23-12.66A87.59,87.59,0,0,1,40,104.49C39.74,56.83,78.26,17.14,125.88,16A88,88,0,0,1,216,104Zm-16,0a72,72,0,0,0-73.74-72c-39,.92-70.47,33.39-70.26,72.39a71.65,71.65,0,0,0,27.64,56.3A32,32,0,0,1,96,186v6h64v-6a32.15,32.15,0,0,1,12.47-25.35A71.65,71.65,0,0,0,200,104Zm-16.11-9.34a57.6,57.6,0,0,0-46.56-46.55,8,8,0,0,0-2.66,15.78c16.57,2.79,30.63,16.85,33.44,33.45A8,8,0,0,0,176,104a9,9,0,0,0,1.35-.11A8,8,0,0,0,183.89,94.66Z"/>',
|
|
57
|
+
"warning-circle" => '<path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z"/>',
|
|
58
|
+
"warning-octagon" => '<path d="M120,136V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0ZM232,91.55v72.9a15.86,15.86,0,0,1-4.69,11.31l-51.55,51.55A15.86,15.86,0,0,1,164.45,232H91.55a15.86,15.86,0,0,1-11.31-4.69L28.69,175.76A15.86,15.86,0,0,1,24,164.45V91.55a15.86,15.86,0,0,1,4.69-11.31L80.24,28.69A15.86,15.86,0,0,1,91.55,24h72.9a15.86,15.86,0,0,1,11.31,4.69l51.55,51.55A15.86,15.86,0,0,1,232,91.55Zm-16,0L164.45,40H91.55L40,91.55v72.9L91.55,216h72.9L216,164.45ZM128,160a12,12,0,1,0,12,12A12,12,0,0,0,128,160Z"/>',
|
|
59
|
+
"siren" => '<path d="M120,16V8a8,8,0,0,1,16,0v8a8,8,0,0,1-16,0Zm80,32a8,8,0,0,0,5.66-2.34l8-8a8,8,0,0,0-11.32-11.32l-8,8A8,8,0,0,0,200,48ZM50.34,45.66A8,8,0,0,0,61.66,34.34l-8-8A8,8,0,0,0,42.34,37.66Zm87,26.45a8,8,0,1,0-2.64,15.78C153.67,91.08,168,108.32,168,128a8,8,0,0,0,16,0C184,100.6,163.93,76.57,137.32,72.11ZM232,176v24a16,16,0,0,1-16,16H40a16,16,0,0,1-16-16V176a16,16,0,0,1,16-16V128a88,88,0,0,1,88.67-88c48.15.36,87.33,40.29,87.33,89v31A16,16,0,0,1,232,176ZM56,160H200V129c0-40-32.05-72.71-71.45-73H128a72,72,0,0,0-72,72Zm160,40V176H40v24H216Z"/>'
|
|
60
|
+
}
|
|
61
|
+
}.freeze
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
# rubocop:enable Layout/LineLength
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "icons/phosphor"
|
|
4
|
+
require_relative "icons/file_types"
|
|
5
|
+
require_relative "renderer"
|
|
6
|
+
|
|
7
|
+
module Docyard
|
|
8
|
+
module Icons
|
|
9
|
+
LIBRARIES = {
|
|
10
|
+
phosphor: PHOSPHOR
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
def self.render(name, weight = "regular")
|
|
14
|
+
icon_data = LIBRARIES.dig(:phosphor, weight, name)
|
|
15
|
+
return nil unless icon_data
|
|
16
|
+
|
|
17
|
+
Renderer.new.render_partial(
|
|
18
|
+
"_icon", {
|
|
19
|
+
name: name,
|
|
20
|
+
icon_data: icon_data
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.render_file_extension(extension)
|
|
26
|
+
svg_content = FileTypes.svg(extension)
|
|
27
|
+
|
|
28
|
+
if svg_content
|
|
29
|
+
Renderer.new.render_partial(
|
|
30
|
+
"_icon_file_extension", {
|
|
31
|
+
extension: extension,
|
|
32
|
+
svg_content: svg_content
|
|
33
|
+
}
|
|
34
|
+
)
|
|
35
|
+
else
|
|
36
|
+
render("file")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/docyard/initializer.rb
CHANGED
|
@@ -6,14 +6,13 @@ module Docyard
|
|
|
6
6
|
class Initializer
|
|
7
7
|
DOCS_DIR = "docs"
|
|
8
8
|
TEMPLATE_DIR = File.join(__dir__, "templates", "markdown")
|
|
9
|
+
CONFIG_TEMPLATE_DIR = File.join(__dir__, "templates", "config")
|
|
9
10
|
|
|
10
11
|
TEMPLATES = {
|
|
11
12
|
"index.md" => "index.md.erb",
|
|
12
|
-
"getting-started/introduction.md" => "getting-started/introduction.md.erb",
|
|
13
13
|
"getting-started/installation.md" => "getting-started/installation.md.erb",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"core-concepts/markdown.md" => "core-concepts/markdown.md.erb"
|
|
14
|
+
"guides/markdown-features.md" => "guides/markdown-features.md.erb",
|
|
15
|
+
"guides/configuration.md" => "guides/configuration.md.erb"
|
|
17
16
|
}.freeze
|
|
18
17
|
|
|
19
18
|
def initialize(path = ".")
|
|
@@ -44,6 +43,8 @@ module Docyard
|
|
|
44
43
|
TEMPLATES.each do |output_name, template_name|
|
|
45
44
|
copy_template(template_name, output_name)
|
|
46
45
|
end
|
|
46
|
+
|
|
47
|
+
create_example_config
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
def copy_template(template_name, output_name)
|
|
@@ -57,20 +58,103 @@ module Docyard
|
|
|
57
58
|
File.write(output_path, content)
|
|
58
59
|
end
|
|
59
60
|
|
|
61
|
+
def create_example_config
|
|
62
|
+
config_path = File.join(@path, "docyard.yml")
|
|
63
|
+
return if File.exist?(config_path)
|
|
64
|
+
|
|
65
|
+
template_path = File.join(CONFIG_TEMPLATE_DIR, "docyard.yml.erb")
|
|
66
|
+
config_content = File.read(template_path)
|
|
67
|
+
|
|
68
|
+
File.write(config_path, config_content)
|
|
69
|
+
end
|
|
70
|
+
|
|
60
71
|
def print_already_exists_error
|
|
61
72
|
puts "Error: #{DOCS_DIR}/ folder already exists"
|
|
62
73
|
puts " Remove it first or run docyard in a different directory"
|
|
63
74
|
end
|
|
64
75
|
|
|
65
76
|
def print_success
|
|
66
|
-
|
|
77
|
+
print_banner
|
|
78
|
+
print_created_files
|
|
79
|
+
print_next_steps
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def print_banner
|
|
83
|
+
puts ""
|
|
84
|
+
puts "┌─────────────────────────────────────────────────────────────┐"
|
|
85
|
+
puts "│ ✓ Docyard initialized successfully │"
|
|
86
|
+
puts "└─────────────────────────────────────────────────────────────┘"
|
|
87
|
+
puts ""
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def print_created_files
|
|
91
|
+
puts "Created files:"
|
|
67
92
|
puts ""
|
|
68
|
-
|
|
69
|
-
TEMPLATES.each_key { |file| puts " #{DOCS_DIR}/#{file}" }
|
|
93
|
+
print_file_tree
|
|
70
94
|
puts ""
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def print_next_steps
|
|
71
98
|
puts "Next steps:"
|
|
72
|
-
puts "
|
|
73
|
-
puts "
|
|
99
|
+
puts ""
|
|
100
|
+
puts " Start development server:"
|
|
101
|
+
puts " docyard serve"
|
|
102
|
+
puts " → http://localhost:4200"
|
|
103
|
+
puts ""
|
|
104
|
+
puts " Build for production:"
|
|
105
|
+
puts " docyard build"
|
|
106
|
+
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}"
|
|
74
158
|
end
|
|
75
159
|
end
|
|
76
160
|
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Docyard
|
|
4
|
+
module LanguageMapping
|
|
5
|
+
TERMINAL_LANGUAGES = %w[bash sh shell powershell].freeze
|
|
6
|
+
|
|
7
|
+
LANGUAGE_TO_EXTENSION = {
|
|
8
|
+
"js" => "js",
|
|
9
|
+
"javascript" => "js",
|
|
10
|
+
"ts" => "ts",
|
|
11
|
+
"typescript" => "ts",
|
|
12
|
+
"jsx" => "jsx",
|
|
13
|
+
"tsx" => "tsx",
|
|
14
|
+
"py" => "py",
|
|
15
|
+
"python" => "py",
|
|
16
|
+
"rb" => "rb",
|
|
17
|
+
"ruby" => "rb",
|
|
18
|
+
"go" => "go",
|
|
19
|
+
"golang" => "go",
|
|
20
|
+
"rs" => "rs",
|
|
21
|
+
"rust" => "rs",
|
|
22
|
+
"php" => "php",
|
|
23
|
+
"html" => "html",
|
|
24
|
+
"htm" => "html",
|
|
25
|
+
"html5" => "html",
|
|
26
|
+
"css" => "css",
|
|
27
|
+
"json" => "json",
|
|
28
|
+
"yaml" => "yaml",
|
|
29
|
+
"yml" => "yaml",
|
|
30
|
+
"toml" => "toml",
|
|
31
|
+
"sql" => "sql",
|
|
32
|
+
"mysql" => "mysql",
|
|
33
|
+
"postgresql" => "pgsql",
|
|
34
|
+
"postgres" => "pgsql",
|
|
35
|
+
"pgsql" => "pgsql",
|
|
36
|
+
"graphql" => "graphql",
|
|
37
|
+
"gql" => "graphql",
|
|
38
|
+
"vue" => "vue",
|
|
39
|
+
"svelte" => "svelte",
|
|
40
|
+
"proto" => "proto",
|
|
41
|
+
"protobuf" => "proto"
|
|
42
|
+
}.freeze
|
|
43
|
+
|
|
44
|
+
def self.extension_for(language)
|
|
45
|
+
LANGUAGE_TO_EXTENSION[language.to_s.downcase]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.terminal_language?(language)
|
|
49
|
+
TERMINAL_LANGUAGES.include?(language.to_s.downcase)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/docyard/markdown.rb
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
require "kramdown"
|
|
4
4
|
require "kramdown-parser-gfm"
|
|
5
5
|
require "yaml"
|
|
6
|
+
require_relative "components/registry"
|
|
7
|
+
require_relative "components/base_processor"
|
|
8
|
+
require_relative "components/callout_processor"
|
|
9
|
+
require_relative "components/tabs_processor"
|
|
10
|
+
require_relative "components/icon_processor"
|
|
11
|
+
require_relative "components/code_block_processor"
|
|
12
|
+
require_relative "components/table_wrapper_processor"
|
|
6
13
|
|
|
7
14
|
module Docyard
|
|
8
15
|
class Markdown
|
|
@@ -34,6 +41,18 @@ module Docyard
|
|
|
34
41
|
frontmatter["description"]
|
|
35
42
|
end
|
|
36
43
|
|
|
44
|
+
def sidebar_icon
|
|
45
|
+
frontmatter.dig("sidebar", "icon")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def sidebar_text
|
|
49
|
+
frontmatter.dig("sidebar", "text")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def sidebar_collapsed
|
|
53
|
+
frontmatter.dig("sidebar", "collapsed")
|
|
54
|
+
end
|
|
55
|
+
|
|
37
56
|
private
|
|
38
57
|
|
|
39
58
|
def parse_frontmatter
|
|
@@ -50,12 +69,17 @@ module Docyard
|
|
|
50
69
|
end
|
|
51
70
|
|
|
52
71
|
def render_html
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
preprocessed_content = Components::Registry.run_preprocessors(content)
|
|
73
|
+
|
|
74
|
+
raw_html = Kramdown::Document.new(
|
|
75
|
+
preprocessed_content,
|
|
55
76
|
input: "GFM",
|
|
56
77
|
hard_wrap: false,
|
|
57
|
-
syntax_highlighter: "rouge"
|
|
78
|
+
syntax_highlighter: "rouge",
|
|
79
|
+
parse_block_html: true
|
|
58
80
|
).to_html
|
|
81
|
+
|
|
82
|
+
Components::Registry.run_postprocessors(raw_html)
|
|
59
83
|
end
|
|
60
84
|
end
|
|
61
85
|
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webrick"
|
|
4
|
+
require_relative "config"
|
|
5
|
+
|
|
6
|
+
module Docyard
|
|
7
|
+
class PreviewServer
|
|
8
|
+
DEFAULT_PORT = 4000
|
|
9
|
+
|
|
10
|
+
attr_reader :port, :output_dir
|
|
11
|
+
|
|
12
|
+
def initialize(port: DEFAULT_PORT)
|
|
13
|
+
@port = port
|
|
14
|
+
@config = Config.load
|
|
15
|
+
@output_dir = File.expand_path(@config.build.output_dir)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def start
|
|
19
|
+
validate_output_directory!
|
|
20
|
+
print_server_info
|
|
21
|
+
|
|
22
|
+
server = create_server
|
|
23
|
+
trap("INT") { shutdown_server(server) }
|
|
24
|
+
|
|
25
|
+
server.start
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def validate_output_directory!
|
|
31
|
+
return if File.directory?(output_dir)
|
|
32
|
+
|
|
33
|
+
abort "Error: #{output_dir}/ directory not found.\n" \
|
|
34
|
+
"Run `docyard build` first to build the site."
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def print_server_info
|
|
38
|
+
puts "Preview server starting..."
|
|
39
|
+
puts "=> Serving from: #{output_dir}/"
|
|
40
|
+
puts "=> Running at: http://localhost:#{port}"
|
|
41
|
+
puts "=> Press Ctrl+C to stop\n"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def create_server
|
|
45
|
+
WEBrick::HTTPServer.new(
|
|
46
|
+
Port: port,
|
|
47
|
+
DocumentRoot: output_dir,
|
|
48
|
+
AccessLog: [],
|
|
49
|
+
Logger: WEBrick::Log.new(File::NULL),
|
|
50
|
+
MimeTypes: mime_types
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def mime_types
|
|
55
|
+
WEBrick::HTTPUtils::DefaultMimeTypes.merge(
|
|
56
|
+
{
|
|
57
|
+
"css" => "text/css",
|
|
58
|
+
"js" => "application/javascript",
|
|
59
|
+
"json" => "application/json",
|
|
60
|
+
"svg" => "image/svg+xml",
|
|
61
|
+
"woff" => "font/woff",
|
|
62
|
+
"woff2" => "font/woff2"
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def shutdown_server(server)
|
|
68
|
+
puts "\nShutting down preview server..."
|
|
69
|
+
server.shutdown
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
require "rack"
|
|
5
5
|
require_relative "sidebar_builder"
|
|
6
|
+
require_relative "constants"
|
|
6
7
|
|
|
7
8
|
module Docyard
|
|
8
9
|
class RackApplication
|
|
9
|
-
def initialize(docs_path:, file_watcher:)
|
|
10
|
+
def initialize(docs_path:, file_watcher:, config: nil)
|
|
10
11
|
@docs_path = docs_path
|
|
11
12
|
@file_watcher = file_watcher
|
|
13
|
+
@config = config
|
|
12
14
|
@router = Router.new(docs_path: docs_path)
|
|
13
|
-
@renderer = Renderer.new
|
|
15
|
+
@renderer = Renderer.new(base_url: config&.build&.base_url || "/")
|
|
14
16
|
@asset_handler = AssetHandler.new
|
|
15
17
|
end
|
|
16
18
|
|
|
@@ -20,7 +22,7 @@ module Docyard
|
|
|
20
22
|
|
|
21
23
|
private
|
|
22
24
|
|
|
23
|
-
attr_reader :docs_path, :file_watcher, :router, :renderer, :asset_handler
|
|
25
|
+
attr_reader :docs_path, :file_watcher, :config, :router, :renderer, :asset_handler
|
|
24
26
|
|
|
25
27
|
def handle_request(env)
|
|
26
28
|
path = env["PATH_INFO"]
|
|
@@ -37,15 +39,82 @@ module Docyard
|
|
|
37
39
|
result = router.resolve(path)
|
|
38
40
|
|
|
39
41
|
if result.found?
|
|
40
|
-
|
|
41
|
-
html = renderer.render_file(result.file_path, sidebar_html: sidebar.to_html)
|
|
42
|
-
[Constants::STATUS_OK, { "Content-Type" => Constants::CONTENT_TYPE_HTML }, [html]]
|
|
42
|
+
render_documentation_page(result.file_path, path)
|
|
43
43
|
else
|
|
44
|
-
|
|
45
|
-
[Constants::STATUS_NOT_FOUND, { "Content-Type" => Constants::CONTENT_TYPE_HTML }, [html]]
|
|
44
|
+
render_not_found_page
|
|
46
45
|
end
|
|
47
46
|
end
|
|
48
47
|
|
|
48
|
+
def render_documentation_page(file_path, current_path)
|
|
49
|
+
html = renderer.render_file(
|
|
50
|
+
file_path,
|
|
51
|
+
sidebar_html: build_sidebar(current_path),
|
|
52
|
+
branding: branding_options
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
[Constants::STATUS_OK, { "Content-Type" => Constants::CONTENT_TYPE_HTML }, [html]]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def render_not_found_page
|
|
59
|
+
html = renderer.render_not_found
|
|
60
|
+
[Constants::STATUS_NOT_FOUND, { "Content-Type" => Constants::CONTENT_TYPE_HTML }, [html]]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def build_sidebar(current_path)
|
|
64
|
+
SidebarBuilder.new(
|
|
65
|
+
docs_path: docs_path,
|
|
66
|
+
current_path: current_path,
|
|
67
|
+
config: config
|
|
68
|
+
).to_html
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def branding_options
|
|
72
|
+
return default_branding unless config
|
|
73
|
+
|
|
74
|
+
default_branding.merge(config_branding_options)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def default_branding
|
|
78
|
+
{
|
|
79
|
+
site_title: Constants::DEFAULT_SITE_TITLE,
|
|
80
|
+
site_description: "",
|
|
81
|
+
logo: Constants::DEFAULT_LOGO_PATH,
|
|
82
|
+
logo_dark: Constants::DEFAULT_LOGO_DARK_PATH,
|
|
83
|
+
favicon: nil,
|
|
84
|
+
display_logo: true,
|
|
85
|
+
display_title: true
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def config_branding_options
|
|
90
|
+
site = config.site
|
|
91
|
+
branding = config.branding
|
|
92
|
+
|
|
93
|
+
{
|
|
94
|
+
site_title: site.title || Constants::DEFAULT_SITE_TITLE,
|
|
95
|
+
site_description: site.description || "",
|
|
96
|
+
logo: resolve_logo(branding.logo, branding.logo_dark),
|
|
97
|
+
logo_dark: resolve_logo_dark(branding.logo, branding.logo_dark),
|
|
98
|
+
favicon: branding.favicon
|
|
99
|
+
}.merge(appearance_options(branding.appearance))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def appearance_options(appearance)
|
|
103
|
+
appearance ||= {}
|
|
104
|
+
{
|
|
105
|
+
display_logo: appearance["logo"] != false,
|
|
106
|
+
display_title: appearance["title"] != false
|
|
107
|
+
}
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def resolve_logo(logo, logo_dark)
|
|
111
|
+
logo || logo_dark || Constants::DEFAULT_LOGO_PATH
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def resolve_logo_dark(logo, logo_dark)
|
|
115
|
+
logo_dark || logo || Constants::DEFAULT_LOGO_DARK_PATH
|
|
116
|
+
end
|
|
117
|
+
|
|
49
118
|
def handle_reload_check(env)
|
|
50
119
|
since = parse_since_timestamp(env)
|
|
51
120
|
reload_needed = file_watcher.changed_since?(since)
|
data/lib/docyard/renderer.rb
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "erb"
|
|
4
|
+
require_relative "constants"
|
|
4
5
|
|
|
5
6
|
module Docyard
|
|
6
7
|
class Renderer
|
|
7
8
|
LAYOUTS_PATH = File.join(__dir__, "templates", "layouts")
|
|
8
9
|
ERRORS_PATH = File.join(__dir__, "templates", "errors")
|
|
10
|
+
PARTIALS_PATH = File.join(__dir__, "templates", "partials")
|
|
9
11
|
|
|
10
|
-
attr_reader :layout_path
|
|
12
|
+
attr_reader :layout_path, :base_url
|
|
11
13
|
|
|
12
|
-
def initialize(layout: "default")
|
|
14
|
+
def initialize(layout: "default", base_url: "/")
|
|
13
15
|
@layout_path = File.join(LAYOUTS_PATH, "#{layout}.html.erb")
|
|
16
|
+
@base_url = normalize_base_url(base_url)
|
|
14
17
|
end
|
|
15
18
|
|
|
16
|
-
def render_file(file_path, sidebar_html: "")
|
|
19
|
+
def render_file(file_path, sidebar_html: "", branding: {})
|
|
17
20
|
markdown_content = File.read(file_path)
|
|
18
21
|
markdown = Markdown.new(markdown_content)
|
|
19
22
|
|
|
@@ -21,17 +24,17 @@ module Docyard
|
|
|
21
24
|
|
|
22
25
|
render(
|
|
23
26
|
content: html_content,
|
|
24
|
-
page_title: markdown.title ||
|
|
25
|
-
sidebar_html: sidebar_html
|
|
27
|
+
page_title: markdown.title || Constants::DEFAULT_SITE_TITLE,
|
|
28
|
+
sidebar_html: sidebar_html,
|
|
29
|
+
branding: branding
|
|
26
30
|
)
|
|
27
31
|
end
|
|
28
32
|
|
|
29
|
-
def render(content:, page_title:
|
|
33
|
+
def render(content:, page_title: Constants::DEFAULT_SITE_TITLE, sidebar_html: "", branding: {})
|
|
30
34
|
template = File.read(layout_path)
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@sidebar_html = sidebar_html
|
|
36
|
+
assign_content_variables(content, page_title, sidebar_html)
|
|
37
|
+
assign_branding_variables(branding)
|
|
35
38
|
|
|
36
39
|
ERB.new(template).result(binding)
|
|
37
40
|
end
|
|
@@ -52,8 +55,52 @@ module Docyard
|
|
|
52
55
|
ERB.new(template).result(binding)
|
|
53
56
|
end
|
|
54
57
|
|
|
58
|
+
def render_partial(name, locals = {})
|
|
59
|
+
partial_path = File.join(PARTIALS_PATH, "#{name}.html.erb")
|
|
60
|
+
template = File.read(partial_path)
|
|
61
|
+
|
|
62
|
+
locals.each { |key, value| instance_variable_set("@#{key}", value) }
|
|
63
|
+
|
|
64
|
+
ERB.new(template).result(binding)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def asset_path(path)
|
|
68
|
+
return path if path.nil? || path.start_with?("http://", "https://")
|
|
69
|
+
|
|
70
|
+
"#{base_url}#{path}"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def link_path(path)
|
|
74
|
+
return path if path.nil? || path.start_with?("http://", "https://")
|
|
75
|
+
|
|
76
|
+
"#{base_url.chomp('/')}#{path}"
|
|
77
|
+
end
|
|
78
|
+
|
|
55
79
|
private
|
|
56
80
|
|
|
81
|
+
def normalize_base_url(url)
|
|
82
|
+
return "/" if url.nil? || url.empty?
|
|
83
|
+
|
|
84
|
+
url = "/#{url}" unless url.start_with?("/")
|
|
85
|
+
url.end_with?("/") ? url : "#{url}/"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def assign_content_variables(content, page_title, sidebar_html)
|
|
89
|
+
@content = content
|
|
90
|
+
@page_title = page_title
|
|
91
|
+
@sidebar_html = sidebar_html
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def assign_branding_variables(branding)
|
|
95
|
+
@site_title = branding[:site_title] || Constants::DEFAULT_SITE_TITLE
|
|
96
|
+
@site_description = branding[:site_description] || ""
|
|
97
|
+
@logo = branding[:logo] || Constants::DEFAULT_LOGO_PATH
|
|
98
|
+
@logo_dark = branding[:logo_dark]
|
|
99
|
+
@favicon = branding[:favicon] || Constants::DEFAULT_FAVICON_PATH
|
|
100
|
+
@display_logo = branding[:display_logo].nil? || branding[:display_logo]
|
|
101
|
+
@display_title = branding[:display_title].nil? || branding[:display_title]
|
|
102
|
+
end
|
|
103
|
+
|
|
57
104
|
def strip_md_from_links(html)
|
|
58
105
|
html.gsub(/href="([^"]+)\.md"/, 'href="\1"')
|
|
59
106
|
end
|