docyard 0.7.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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -1
  3. data/CHANGELOG.md +20 -1
  4. data/lib/docyard/build/asset_bundler.rb +22 -7
  5. data/lib/docyard/build/file_copier.rb +49 -27
  6. data/lib/docyard/build/sitemap_generator.rb +6 -6
  7. data/lib/docyard/build/static_generator.rb +85 -12
  8. data/lib/docyard/builder.rb +6 -6
  9. data/lib/docyard/config/branding_resolver.rb +126 -17
  10. data/lib/docyard/config/constants.rb +6 -4
  11. data/lib/docyard/config/validator.rb +122 -99
  12. data/lib/docyard/config.rb +36 -43
  13. data/lib/docyard/initializer.rb +15 -76
  14. data/lib/docyard/navigation/breadcrumb_builder.rb +133 -0
  15. data/lib/docyard/navigation/prev_next_builder.rb +4 -1
  16. data/lib/docyard/navigation/sidebar/children_discoverer.rb +51 -0
  17. data/lib/docyard/navigation/sidebar/config_parser.rb +136 -108
  18. data/lib/docyard/navigation/sidebar/file_resolver.rb +78 -0
  19. data/lib/docyard/navigation/sidebar/file_system_scanner.rb +2 -1
  20. data/lib/docyard/navigation/sidebar/item.rb +45 -7
  21. data/lib/docyard/navigation/sidebar/local_config_loader.rb +51 -0
  22. data/lib/docyard/navigation/sidebar/metadata_extractor.rb +69 -0
  23. data/lib/docyard/navigation/sidebar/metadata_reader.rb +47 -0
  24. data/lib/docyard/navigation/sidebar/path_prefixer.rb +34 -0
  25. data/lib/docyard/navigation/sidebar/renderer.rb +55 -37
  26. data/lib/docyard/navigation/sidebar/sorter.rb +21 -0
  27. data/lib/docyard/navigation/sidebar/tree_builder.rb +99 -26
  28. data/lib/docyard/navigation/sidebar/tree_filter.rb +55 -0
  29. data/lib/docyard/navigation/sidebar_builder.rb +105 -36
  30. data/lib/docyard/rendering/icon_helpers.rb +13 -0
  31. data/lib/docyard/rendering/icons/phosphor.rb +23 -1
  32. data/lib/docyard/rendering/markdown.rb +5 -0
  33. data/lib/docyard/rendering/renderer.rb +74 -34
  34. data/lib/docyard/rendering/template_resolver.rb +172 -0
  35. data/lib/docyard/routing/fallback_resolver.rb +92 -0
  36. data/lib/docyard/search/build_indexer.rb +1 -1
  37. data/lib/docyard/search/dev_indexer.rb +51 -6
  38. data/lib/docyard/search/pagefind_support.rb +2 -0
  39. data/lib/docyard/server/asset_handler.rb +24 -19
  40. data/lib/docyard/server/pagefind_handler.rb +63 -0
  41. data/lib/docyard/server/preview_server.rb +1 -1
  42. data/lib/docyard/server/rack_application.rb +81 -64
  43. data/lib/docyard/templates/assets/css/code.css +18 -51
  44. data/lib/docyard/templates/assets/css/components/breadcrumbs.css +143 -0
  45. data/lib/docyard/templates/assets/css/components/callout.css +67 -67
  46. data/lib/docyard/templates/assets/css/components/code-block.css +180 -282
  47. data/lib/docyard/templates/assets/css/components/heading-anchor.css +28 -15
  48. data/lib/docyard/templates/assets/css/components/icon.css +0 -1
  49. data/lib/docyard/templates/assets/css/components/logo.css +0 -2
  50. data/lib/docyard/templates/assets/css/components/nav-menu.css +237 -0
  51. data/lib/docyard/templates/assets/css/components/navigation.css +186 -167
  52. data/lib/docyard/templates/assets/css/components/prev-next.css +76 -47
  53. data/lib/docyard/templates/assets/css/components/search.css +186 -174
  54. data/lib/docyard/templates/assets/css/components/tab-bar.css +163 -0
  55. data/lib/docyard/templates/assets/css/components/table-of-contents.css +127 -114
  56. data/lib/docyard/templates/assets/css/components/tabs.css +119 -160
  57. data/lib/docyard/templates/assets/css/components/theme-toggle.css +48 -44
  58. data/lib/docyard/templates/assets/css/landing.css +815 -0
  59. data/lib/docyard/templates/assets/css/layout.css +489 -87
  60. data/lib/docyard/templates/assets/css/main.css +1 -3
  61. data/lib/docyard/templates/assets/css/markdown.css +111 -93
  62. data/lib/docyard/templates/assets/css/reset.css +0 -3
  63. data/lib/docyard/templates/assets/css/typography.css +43 -41
  64. data/lib/docyard/templates/assets/css/variables.css +268 -208
  65. data/lib/docyard/templates/assets/favicon.svg +7 -8
  66. data/lib/docyard/templates/assets/fonts/Inter-Variable.ttf +0 -0
  67. data/lib/docyard/templates/assets/js/components/code-block.js +24 -42
  68. data/lib/docyard/templates/assets/js/components/heading-anchor.js +26 -24
  69. data/lib/docyard/templates/assets/js/components/navigation.js +181 -70
  70. data/lib/docyard/templates/assets/js/components/search.js +0 -75
  71. data/lib/docyard/templates/assets/js/components/sidebar-toggle.js +29 -0
  72. data/lib/docyard/templates/assets/js/components/tab-navigation.js +145 -0
  73. data/lib/docyard/templates/assets/js/components/table-of-contents.js +153 -66
  74. data/lib/docyard/templates/assets/js/components/tabs.js +31 -69
  75. data/lib/docyard/templates/assets/js/theme.js +0 -3
  76. data/lib/docyard/templates/assets/logo-dark.svg +8 -2
  77. data/lib/docyard/templates/assets/logo.svg +7 -4
  78. data/lib/docyard/templates/config/docyard.yml.erb +37 -34
  79. data/lib/docyard/templates/errors/404.html.erb +1 -1
  80. data/lib/docyard/templates/errors/500.html.erb +1 -1
  81. data/lib/docyard/templates/layouts/default.html.erb +18 -67
  82. data/lib/docyard/templates/layouts/splash.html.erb +176 -0
  83. data/lib/docyard/templates/partials/_breadcrumbs.html.erb +24 -0
  84. data/lib/docyard/templates/partials/_code_block.html.erb +5 -3
  85. data/lib/docyard/templates/partials/_doc_footer.html.erb +25 -0
  86. data/lib/docyard/templates/partials/_features.html.erb +15 -0
  87. data/lib/docyard/templates/partials/_footer.html.erb +42 -0
  88. data/lib/docyard/templates/partials/_head.html.erb +22 -0
  89. data/lib/docyard/templates/partials/_header.html.erb +49 -0
  90. data/lib/docyard/templates/partials/_heading_anchor.html.erb +3 -1
  91. data/lib/docyard/templates/partials/_hero.html.erb +27 -0
  92. data/lib/docyard/templates/partials/_nav_group.html.erb +25 -11
  93. data/lib/docyard/templates/partials/_nav_leaf.html.erb +1 -1
  94. data/lib/docyard/templates/partials/_nav_menu.html.erb +42 -0
  95. data/lib/docyard/templates/partials/_nav_nested_section.html.erb +11 -0
  96. data/lib/docyard/templates/partials/_nav_section.html.erb +1 -1
  97. data/lib/docyard/templates/partials/_prev_next.html.erb +8 -2
  98. data/lib/docyard/templates/partials/_scripts.html.erb +7 -0
  99. data/lib/docyard/templates/partials/_search_modal.html.erb +2 -6
  100. data/lib/docyard/templates/partials/_search_trigger.html.erb +2 -6
  101. data/lib/docyard/templates/partials/_sidebar.html.erb +21 -4
  102. data/lib/docyard/templates/partials/_tab_bar.html.erb +25 -0
  103. data/lib/docyard/templates/partials/_table_of_contents.html.erb +12 -12
  104. data/lib/docyard/templates/partials/_table_of_contents_toggle.html.erb +1 -3
  105. data/lib/docyard/templates/partials/_tabs.html.erb +2 -2
  106. data/lib/docyard/templates/partials/_theme_toggle.html.erb +2 -11
  107. data/lib/docyard/version.rb +1 -1
  108. metadata +33 -5
  109. data/lib/docyard/templates/markdown/getting-started/installation.md.erb +0 -77
  110. data/lib/docyard/templates/markdown/guides/configuration.md.erb +0 -202
  111. data/lib/docyard/templates/markdown/guides/markdown-features.md.erb +0 -247
  112. data/lib/docyard/templates/markdown/index.md.erb +0 -82
@@ -1,42 +1,45 @@
1
1
  # Docyard Configuration
2
2
  # Documentation: https://github.com/yourusername/docyard
3
3
 
4
- # Site Information
5
- site:
6
- title: "My Documentation"
7
- description: "Documentation for my project"
4
+ # Site Identity
5
+ title: "My Documentation"
6
+ description: "Documentation for my project"
8
7
 
9
- # Custom Branding (Optional)
10
- # Paths relative to docs/ directory, or use URLs for CDN-hosted assets
11
- branding:
12
- # logo: "assets/logo.svg" # Light mode logo
13
- # logo_dark: "assets/logo-dark.svg" # Dark mode logo (optional, falls back to 'logo')
14
- # favicon: "assets/favicon.svg" # Browser tab icon
15
- # appearance:
16
- # logo: true # Show logo in header
17
- # title: true # Show site title in header
8
+ # Branding (Optional)
9
+ # Docyard auto-detects these files from docs/public/:
10
+ # - logo.svg or logo.png (and logo-dark.svg for dark mode)
11
+ # - favicon.ico, favicon.svg, or favicon.png
12
+ # Only configure if you need custom paths or filenames.
13
+ # branding:
14
+ # logo: "custom-logo.svg" # Override auto-detected logo
15
+ # favicon: "custom.ico" # Override auto-detected favicon
16
+ # credits: true # Show "Built with Docyard" link
18
17
 
19
- # Sidebar Navigation (Optional)
20
- # Customize the order and organization of your documentation pages
21
- # Without this, sidebar is auto-generated from docs/ folder structure
22
- # sidebar:
23
- # items:
24
- # - installation # Simple page reference
25
- #
26
- # - guides: # Nested group
27
- # text: "User Guides"
28
- # icon: "book-open" # Icon from phosphoricons.com
29
- # items:
30
- # - markdown-features
31
- # - configuration
32
- #
33
- # - text: "GitHub" # External link
34
- # link: "https://github.com/youruser/yourrepo"
35
- # icon: "github-logo"
36
- # target: "_blank"
18
+ # Social Links (Optional)
19
+ # These appear in the footer
20
+ # socials:
21
+ # github: https://github.com/user/repo
22
+ # twitter: https://twitter.com/handle
23
+
24
+ # Tab Navigation (Optional)
25
+ # Use tabs to organize large documentation into sections
26
+ # tabs:
27
+ # - text: Guide
28
+ # href: /guide
29
+ # - text: API Reference
30
+ # href: /api
31
+ # - text: Blog
32
+ # href: https://blog.example.com
33
+ # external: true
34
+
35
+ # Search Configuration
36
+ # search:
37
+ # enabled: true
38
+ # placeholder: "Search documentation..."
39
+ # exclude:
40
+ # - /drafts/*
37
41
 
38
42
  # Build Configuration
39
43
  build:
40
- output_dir: "dist" # Output directory for static files
41
- base_url: "/" # Base URL for deployment (e.g., "/docs/" for subdirectory)
42
- clean: true # Clean output directory before building
44
+ output: "dist" # Output directory for static files
45
+ base: "/" # Base URL for deployment (e.g., "/docs/" for subdirectory)
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>404 - Page Not Found</title>
7
- <link rel="stylesheet" href="/assets/css/main.css">
7
+ <link rel="stylesheet" href="/_docyard/css/main.css">
8
8
  </head>
9
9
  <body>
10
10
  <main>
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>500 - Server Error</title>
7
- <link rel="stylesheet" href="/assets/css/main.css">
7
+ <link rel="stylesheet" href="/_docyard/css/main.css">
8
8
  </head>
9
9
  <body>
10
10
  <main>
@@ -1,99 +1,50 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="description" content="<%= @site_description %>">
7
- <title><%= @page_title %> | <%= @site_title %></title>
8
- <link rel="icon" href="<%= asset_path(@favicon) %>" type="image/svg+xml">
9
-
10
- <!-- Prevent flash of wrong theme -->
11
- <script>
12
- (function() {
13
- const theme = localStorage.getItem('theme') ||
14
- (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
15
- document.documentElement.classList.toggle('dark', theme === 'dark');
16
- })();
17
- </script>
18
-
19
- <link rel="stylesheet" href="/assets/css/main.css">
4
+ <%= render_partial('_head') %>
20
5
  </head>
21
- <body>
22
- <!-- Skip to main content for accessibility -->
6
+ <body<%= ' class="has-tabs"' if @has_tabs %>>
23
7
  <a href="#main-content" class="skip-link">Skip to main content</a>
24
8
 
25
- <!-- Primary Header -->
26
- <header class="header">
27
- <div class="header-content">
28
- <a href="<%= link_path('/') %>" class="header-logo">
29
- <% if @display_logo %>
30
- <div class="site-logo-container">
31
- <% if @logo %>
32
- <img src="<%= asset_path(@logo) %>" alt="<%= @site_title %>" class="site-logo site-logo-light">
33
- <% end %>
34
- <% if @logo_dark %>
35
- <img src="<%= asset_path(@logo_dark) %>" alt="<%= @site_title %>" class="site-logo site-logo-dark">
36
- <% else %>
37
- <img src="<%= asset_path(@logo) %>" alt="<%= @site_title %>" class="site-logo site-logo-dark">
38
- <% end %>
39
- </div>
40
- <% end %>
41
- <% if @display_title %>
42
- <span class="header-title"><%= @site_title %></span>
43
- <% end %>
44
- </a>
45
-
46
- <% if @search_enabled %>
47
- <div class="header-center">
48
- <%= render_partial('_search_trigger') %>
49
- </div>
50
- <% end %>
51
-
52
- <div class="header-actions">
53
- <%= render_partial('_theme_toggle') %>
54
- </div>
55
- </div>
56
- </header>
9
+ <%= render_partial('_header') %>
10
+ <%= render_partial('_tab_bar') %>
11
+ <%= render_partial('_nav_menu') %>
57
12
 
58
- <!-- Secondary Header (Mobile Navigation) -->
59
13
  <div class="secondary-header">
60
14
  <button class="secondary-header-menu" aria-label="Toggle navigation menu" aria-expanded="false">
61
- <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor" width="18" height="18">
62
- <path d="M224,128a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16H216A8,8,0,0,1,224,128ZM40,72H216a8,8,0,0,0,0-16H40a8,8,0,0,0,0,16ZM216,184H40a8,8,0,0,0,0,16H216a8,8,0,0,0,0-16Z"></path>
63
- </svg>
15
+ <%= icon(:sidebar) %>
64
16
  <span>Menu</span>
65
17
  </button>
66
18
 
67
19
  <%= render_partial('_table_of_contents_toggle') %>
68
20
  </div>
69
21
 
70
- <!-- Mobile overlay -->
71
22
  <div class="mobile-overlay" aria-hidden="true"></div>
72
23
 
73
24
  <div class="layout">
74
- <!-- Sidebar navigation -->
75
25
  <%= @sidebar_html %>
76
26
 
77
- <!-- Main content area -->
78
27
  <div class="layout-main">
79
28
  <main id="main-content" class="content" data-pagefind-body>
29
+ <%= render_partial('_breadcrumbs') %>
80
30
  <%= @content %>
81
31
 
82
- <!-- Previous/Next Navigation -->
83
32
  <%= @prev_next_html %>
33
+
34
+ <div class="doc-footer-mobile">
35
+ <%= render_partial('_doc_footer') %>
36
+ </div>
84
37
  </main>
85
38
  </div>
86
39
 
87
- <!-- Table of contents -->
88
- <%= render_partial('_table_of_contents') %>
40
+ <aside class="doc-aside">
41
+ <%= render_partial('_table_of_contents') %>
42
+ <div class="doc-footer-desktop">
43
+ <%= render_partial('_doc_footer') %>
44
+ </div>
45
+ </aside>
89
46
  </div>
90
47
 
91
- <% if @search_enabled %>
92
- <%= render_partial('_search_modal') %>
93
- <% end %>
94
-
95
- <script src="/assets/js/theme.js"></script>
96
- <script src="/assets/js/components.js"></script>
97
- <script src="/assets/js/reload.js"></script>
48
+ <%= render_partial('_scripts') %>
98
49
  </body>
99
50
  </html>
@@ -0,0 +1,176 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <%= render_partial('_head') %>
5
+ </head>
6
+ <body class="splash-page<%= ' has-sidebar' if @show_sidebar %><%= ' has-tabs' if @has_tabs %>">
7
+ <a href="#main-content" class="skip-link">Skip to main content</a>
8
+
9
+ <%= render_partial('_header') %>
10
+ <%= render_partial('_tab_bar') %>
11
+ <%= render_partial('_nav_menu') %>
12
+
13
+ <% if @show_sidebar %>
14
+ <div class="secondary-header">
15
+ <button class="secondary-header-menu" aria-label="Toggle navigation menu" aria-expanded="false">
16
+ <%= icon(:sidebar) %>
17
+ <span>Menu</span>
18
+ </button>
19
+ </div>
20
+
21
+ <div class="mobile-overlay" aria-hidden="true"></div>
22
+
23
+ <div class="layout">
24
+ <%= @sidebar_html %>
25
+
26
+ <div class="layout-main">
27
+ <% end %>
28
+
29
+ <main id="main-content" class="splash-content">
30
+ <% if @hero %>
31
+ <%
32
+ hero_class = @hero[:image] ? 'hero hero--with-image' : 'hero hero--centered'
33
+ bg_style = @hero[:background] || 'grid'
34
+ %>
35
+ <section class="<%= hero_class %>">
36
+ <% if bg_style != 'none' %>
37
+ <div class="hero-bg hero-bg--<%= bg_style %>" aria-hidden="true">
38
+ <% if bg_style == 'glow' %>
39
+ <div class="hero-bg-orb hero-bg-orb--1"></div>
40
+ <div class="hero-bg-orb hero-bg-orb--2"></div>
41
+ <div class="hero-bg-orb hero-bg-orb--3"></div>
42
+ <% elsif bg_style == 'mesh' %>
43
+ <div class="hero-bg-mesh"></div>
44
+ <% end %>
45
+ </div>
46
+ <% end %>
47
+
48
+ <div class="hero-content">
49
+ <% if @hero[:badge] %>
50
+ <div class="hero-badge">
51
+ <span class="hero-badge-dot"></span>
52
+ <span class="hero-badge-text"><%= @hero[:badge] %></span>
53
+ </div>
54
+ <% end %>
55
+ <% if @hero[:title] %>
56
+ <%
57
+ title_class = @hero[:gradient] ? 'hero-title hero-title--gradient' : 'hero-title'
58
+ %>
59
+ <h1 class="<%= title_class %>"><%= @hero[:title] %></h1>
60
+ <% end %>
61
+ <% if @hero[:tagline] %>
62
+ <p class="hero-tagline"><%= @hero[:tagline] %></p>
63
+ <% end %>
64
+ <% if @hero[:actions]&.any? %>
65
+ <div class="hero-actions">
66
+ <% @hero[:actions].each do |action| %>
67
+ <%
68
+ is_external = action[:link]&.start_with?('http')
69
+ target_attr = action[:target] || (is_external ? '_blank' : nil)
70
+ rel_attr = action[:rel] || (is_external ? 'noopener noreferrer' : nil)
71
+ link_attrs = []
72
+ link_attrs << "target=\"#{target_attr}\"" if target_attr
73
+ link_attrs << "rel=\"#{rel_attr}\"" if rel_attr
74
+ %>
75
+ <a href="<%= link_path(action[:link]) %>" class="hero-action hero-action--<%= action[:variant] || 'primary' %>"<%= link_attrs.any? ? ' ' + link_attrs.join(' ') : '' %>>
76
+ <% if action[:icon] %>
77
+ <span class="hero-action-icon"><%= icon(action[:icon]) %></span>
78
+ <% end %>
79
+ <span><%= action[:text] %></span>
80
+ <% if action[:variant] != "secondary" %>
81
+ <svg class="hero-action-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
82
+ <% end %>
83
+ </a>
84
+ <% end %>
85
+ </div>
86
+ <% end %>
87
+ </div>
88
+ <% if @hero[:image] %>
89
+ <div class="hero-image">
90
+ <% if @hero[:image][:light] || @hero[:image][:dark] %>
91
+ <% if @hero[:image][:light] %>
92
+ <img src="<%= asset_path(@hero[:image][:light]) %>" alt="<%= @hero[:image][:alt] || '' %>" loading="eager" class="hero-image-light">
93
+ <% end %>
94
+ <% if @hero[:image][:dark] %>
95
+ <img src="<%= asset_path(@hero[:image][:dark]) %>" alt="<%= @hero[:image][:alt] || '' %>" loading="eager" class="hero-image-dark">
96
+ <% end %>
97
+ <% else %>
98
+ <img src="<%= asset_path(@hero[:image][:src]) %>" alt="<%= @hero[:image][:alt] || '' %>" loading="eager">
99
+ <% end %>
100
+ </div>
101
+ <% end %>
102
+
103
+ </section>
104
+ <% end %>
105
+
106
+ <% if @features&.any? %>
107
+ <section class="features-section">
108
+ <% if @features_header %>
109
+ <div class="features-header">
110
+ <% if @features_header[:label] %>
111
+ <p class="features-label"><%= @features_header[:label] %></p>
112
+ <% end %>
113
+ <% if @features_header[:title] %>
114
+ <h2 class="features-title"><%= @features_header[:title] %></h2>
115
+ <% end %>
116
+ <% if @features_header[:description] %>
117
+ <p class="features-description"><%= @features_header[:description] %></p>
118
+ <% end %>
119
+ </div>
120
+ <% end %>
121
+
122
+ <div class="features-magazine">
123
+ <% @features.each_with_index do |feature, index| %>
124
+ <%
125
+ icon_color = feature[:color] || 'primary'
126
+ size_class = feature[:size] ? "feature-card--#{feature[:size]}" : ''
127
+ has_link = feature[:link] && !feature[:link].to_s.strip.empty?
128
+ tag = has_link ? 'a' : 'div'
129
+
130
+ feature_link_attrs = []
131
+ if has_link
132
+ feature_link_attrs << "href=\"#{link_path(feature[:link])}\""
133
+ is_external = feature[:link]&.start_with?('http')
134
+ target_attr = feature[:target] || (is_external ? '_blank' : nil)
135
+ rel_attr = feature[:rel] || (is_external ? 'noopener noreferrer' : nil)
136
+ feature_link_attrs << "target=\"#{target_attr}\"" if target_attr
137
+ feature_link_attrs << "rel=\"#{rel_attr}\"" if rel_attr
138
+ end
139
+ %>
140
+ <<%= tag %> <%= feature_link_attrs.join(' ') %> class="feature-card <%= size_class %>" style="--card-color: var(--feature-<%= icon_color %>)">
141
+ <% if feature[:icon] %>
142
+ <span class="feature-icon feature-icon--<%= icon_color %>"><%= icon(feature[:icon]) %></span>
143
+ <% end %>
144
+ <h3 class="feature-title"><%= feature[:title] %></h3>
145
+ <% if feature[:description] %>
146
+ <p class="feature-description"><%= feature[:description] %></p>
147
+ <% end %>
148
+ <% if has_link %>
149
+ <div class="feature-arrow">
150
+ <span><%= feature[:link_text] || 'Learn more' %></span>
151
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
152
+ </div>
153
+ <% end %>
154
+ </<%= tag %>>
155
+ <% end %>
156
+ </div>
157
+ </section>
158
+ <% end %>
159
+
160
+ <% if @content && !@content.strip.empty? %>
161
+ <section class="splash-markdown">
162
+ <%= @content %>
163
+ </section>
164
+ <% end %>
165
+ </main>
166
+
167
+ <% if @show_sidebar %>
168
+ </div>
169
+ </div>
170
+ <% end %>
171
+
172
+ <%= render_partial('_footer') %>
173
+
174
+ <%= render_partial('_scripts') %>
175
+ </body>
176
+ </html>
@@ -0,0 +1,24 @@
1
+ <% if @breadcrumbs&.should_show? %>
2
+ <nav class="breadcrumbs<%= ' breadcrumbs--single' if @breadcrumbs.items.length == 1 %>" aria-label="Breadcrumb">
3
+ <button class="breadcrumb-toggle" aria-label="Toggle sidebar" aria-expanded="true" type="button">
4
+ <%= icon(:sidebar) %>
5
+ </button>
6
+
7
+ <ol class="breadcrumb-list">
8
+ <% @breadcrumbs.items.each_with_index do |item, index| %>
9
+ <li class="breadcrumb-item<%= ' breadcrumb-item--current' if item.current %><%= ' breadcrumb-item--ellipsis' if item.title == '...' %>">
10
+ <% if item.title == '...' %>
11
+ <span class="breadcrumb-ellipsis" aria-hidden="true">...</span>
12
+ <% elsif item.current %>
13
+ <span class="breadcrumb-text" aria-current="page"><%= item.title %></span>
14
+ <% else %>
15
+ <a href="<%= link_path(item.href) %>" class="breadcrumb-link"><%= item.title %></a>
16
+ <% end %>
17
+ </li>
18
+ <% unless index == @breadcrumbs.items.length - 1 %>
19
+ <li class="breadcrumb-separator" aria-hidden="true">/</li>
20
+ <% end %>
21
+ <% end %>
22
+ </ol>
23
+ </nav>
24
+ <% end %>
@@ -2,11 +2,12 @@
2
2
  <% if has_title %>
3
3
  <div class="docyard-code-block__header">
4
4
  <% if @icon %>
5
- <span class="docyard-code-block__icon"><% if @icon_source == "file-extension" %><%= Docyard::Icons.render_file_extension(@icon) %><% elsif @icon_source == "phosphor" %><%= Docyard::Icons.render(@icon) %><% end %></span>
5
+ <span class="docyard-code-block__icon"><% if @icon_source == "file-extension" %><%= icon_file_extension(@icon) %><% elsif @icon_source == "phosphor" %><%= icon(@icon) %><% end %></span>
6
6
  <% end %>
7
7
  <span class="docyard-code-block__title" title="<%= @title %>"><%= @title %></span>
8
8
  <button class="docyard-code-block__copy" aria-label="Copy code to clipboard" data-code="<%= @code_text %>">
9
- <%= @copy_icon %>
9
+ <span class="docyard-code-block__copy-icon"><%= @copy_icon %></span>
10
+ <span class="docyard-code-block__copy-text">Copy</span>
10
11
  </button>
11
12
  </div>
12
13
  <% end %>
@@ -47,7 +48,8 @@
47
48
  </div>
48
49
  <% unless has_title %>
49
50
  <button class="docyard-code-block__copy" aria-label="Copy code to clipboard" data-code="<%= @code_text %>">
50
- <%= @copy_icon %>
51
+ <span class="docyard-code-block__copy-icon"><%= @copy_icon %></span>
52
+ <span class="docyard-code-block__copy-text">Copy</span>
51
53
  </button>
52
54
  <% end %>
53
55
  </div>
@@ -0,0 +1,25 @@
1
+ <% has_social = @social&.any? %>
2
+ <% show_footer = has_social || @credits || @copyright %>
3
+
4
+ <% if show_footer %>
5
+ <div class="site-footer">
6
+ <% if has_social %>
7
+ <div class="site-footer__socials">
8
+ <% @social.each do |social| %>
9
+ <a href="<%= social[:url] %>" class="site-footer__link" target="_blank" rel="noopener noreferrer" aria-label="<%= social[:platform].capitalize %>">
10
+ <%= icon(social[:icon]) %>
11
+ </a>
12
+ <% end %>
13
+ </div>
14
+ <% end %>
15
+
16
+ <div class="site-footer__credits">
17
+ <% if @credits %>
18
+ <a href="https://docyard.dev" target="_blank" rel="noopener noreferrer" class="site-footer__attribution">Built with Docyard</a>
19
+ <% end %>
20
+ <% if @copyright %>
21
+ <span class="site-footer__copyright"><%= icon(:copyright) %> <%= @copyright %></span>
22
+ <% end %>
23
+ </div>
24
+ </div>
25
+ <% end %>
@@ -0,0 +1,15 @@
1
+ <section class="features">
2
+ <div class="features-grid">
3
+ <% @features.each do |feature| %>
4
+ <div class="feature-card">
5
+ <% if feature[:icon] %>
6
+ <span class="feature-icon"><%= icon(feature[:icon]) %></span>
7
+ <% end %>
8
+ <h3 class="feature-title"><%= feature[:title] %></h3>
9
+ <% if feature[:description] %>
10
+ <p class="feature-description"><%= feature[:description] %></p>
11
+ <% end %>
12
+ </div>
13
+ <% end %>
14
+ </div>
15
+ </section>
@@ -0,0 +1,42 @@
1
+ <% has_footer_links = @footer_links&.any? %>
2
+ <% has_social = @social&.any? %>
3
+ <% show_footer = has_footer_links || has_social || @credits %>
4
+
5
+ <% if show_footer %>
6
+ <footer class="footer">
7
+ <%
8
+ # Determine layout class
9
+ footer_class = "footer-content"
10
+ if !@credits && !has_social && has_footer_links
11
+ footer_class += " footer-content--no-attribution"
12
+ elsif !has_footer_links && !has_social && @credits
13
+ footer_class += " footer-content--centered"
14
+ elsif !has_footer_links && has_social && !@credits
15
+ footer_class += " footer-content--centered"
16
+ end
17
+ %>
18
+ <div class="<%= footer_class %>">
19
+ <% if @credits %>
20
+ <a href="https://docyard.org" target="_blank" rel="noopener noreferrer" class="footer-attribution">Built with Docyard</a>
21
+ <% end %>
22
+
23
+ <% if has_footer_links %>
24
+ <nav class="footer-links">
25
+ <% @footer_links.each do |link| %>
26
+ <a href="<%= link[:link]&.start_with?('http') ? link[:link] : link_path(link[:link]) %>"<%= link[:link]&.start_with?('http') ? ' target="_blank" rel="noopener noreferrer"' : '' %>><%= link[:text] %></a>
27
+ <% end %>
28
+ </nav>
29
+ <% end %>
30
+
31
+ <% if has_social %>
32
+ <div class="footer-socials">
33
+ <% @social.each do |social| %>
34
+ <a href="<%= social[:url] %>" target="_blank" rel="noopener noreferrer" aria-label="<%= social[:platform].capitalize %>">
35
+ <%= icon(social[:icon]) %>
36
+ </a>
37
+ <% end %>
38
+ </div>
39
+ <% end %>
40
+ </div>
41
+ </footer>
42
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <meta charset="UTF-8">
2
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
3
+ <meta name="description" content="<%= @site_description %>">
4
+ <meta name="view-transition" content="same-origin">
5
+ <title><%= @page_title %> | <%= @site_title %></title>
6
+ <link rel="icon" href="<%= asset_path(@favicon) %>" type="image/svg+xml">
7
+
8
+ <link rel="preload" href="/_docyard/fonts/Inter-Variable.ttf" as="font" type="font/ttf" crossorigin>
9
+
10
+ <script>
11
+ (function() {
12
+ const theme = localStorage.getItem('theme') ||
13
+ (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
14
+ document.documentElement.classList.toggle('dark', theme === 'dark');
15
+
16
+ if (localStorage.getItem('docyard_sidebar_collapsed') === 'true') {
17
+ document.documentElement.classList.add('sidebar-collapsed');
18
+ }
19
+ })();
20
+ </script>
21
+
22
+ <link rel="stylesheet" href="/_docyard/css/main.css">
@@ -0,0 +1,49 @@
1
+ <header class="header">
2
+ <div class="header-content">
3
+ <a href="<%= link_path('/') %>" class="header-logo">
4
+ <% if @has_custom_logo %>
5
+ <div class="site-logo-container">
6
+ <img src="<%= asset_path(@logo) %>" alt="<%= @site_title %>" class="site-logo site-logo-light">
7
+ <% if @logo_dark %>
8
+ <img src="<%= asset_path(@logo_dark) %>" alt="<%= @site_title %>" class="site-logo site-logo-dark">
9
+ <% else %>
10
+ <img src="<%= asset_path(@logo) %>" alt="<%= @site_title %>" class="site-logo site-logo-dark">
11
+ <% end %>
12
+ </div>
13
+ <% else %>
14
+ <span class="header-title"><%= @site_title %></span>
15
+ <% end %>
16
+ </a>
17
+
18
+ <% if @search_enabled %>
19
+ <div class="header-center">
20
+ <%= render_partial('_search_trigger') %>
21
+ </div>
22
+ <% end %>
23
+
24
+ <div class="header-actions">
25
+ <% if @header_ctas&.any? %>
26
+ <div class="header-ctas">
27
+ <% @header_ctas.sort_by { |cta| cta[:variant] == 'secondary' ? 0 : 1 }.each do |cta| %>
28
+ <a href="<%= cta[:external] ? cta[:href] : link_path(cta[:href]) %>"
29
+ class="header-cta header-cta--<%= cta[:variant] || 'primary' %>"
30
+ <%= 'target="_blank" rel="noopener noreferrer"' if cta[:external] %>>
31
+ <%= cta[:text] %>
32
+ <% if cta[:variant] != 'secondary' %>
33
+ <svg class="header-cta-arrow" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
34
+ <path d="M9 5l7 7-7 7"/>
35
+ </svg>
36
+ <% end %>
37
+ </a>
38
+ <% end %>
39
+ </div>
40
+ <% end %>
41
+ <%= render_partial('_theme_toggle') %>
42
+ <% if @has_tabs %>
43
+ <button class="nav-menu-btn" id="navMenuBtn" aria-label="Toggle navigation menu" aria-expanded="false">
44
+ <%= icon(:equals) %>
45
+ </button>
46
+ <% end %>
47
+ </div>
48
+ </div>
49
+ </header>
@@ -1 +1,3 @@
1
- <a href="#<%= @id %>" class="heading-anchor" aria-label="Link to this section" data-heading-id="<%= @id %>" data-pagefind-ignore>#</a>
1
+ <a href="#<%= @id %>" class="heading-anchor" aria-label="Link to this section" data-heading-id="<%= @id %>" data-pagefind-ignore>
2
+ <%= icon(:link_simple) %>
3
+ </a>
@@ -0,0 +1,27 @@
1
+ <section class="hero">
2
+ <div class="hero-content">
3
+ <% if @title %>
4
+ <h1 class="hero-title"><%= @title %></h1>
5
+ <% end %>
6
+ <% if @tagline %>
7
+ <p class="hero-tagline"><%= @tagline %></p>
8
+ <% end %>
9
+ <% if @actions&.any? %>
10
+ <div class="hero-actions">
11
+ <% @actions.each do |action| %>
12
+ <a href="<%= link_path(action[:link]) %>" class="hero-action hero-action--<%= action[:variant] || 'primary' %>">
13
+ <%= action[:text] %>
14
+ <% if action[:variant] == "primary" || action[:variant].nil? %>
15
+ <%= icon(:arrow_right) %>
16
+ <% end %>
17
+ </a>
18
+ <% end %>
19
+ </div>
20
+ <% end %>
21
+ </div>
22
+ <% if @image %>
23
+ <div class="hero-image">
24
+ <img src="<%= link_path(@image[:src]) %>" alt="<%= @image[:alt] || '' %>">
25
+ </div>
26
+ <% end %>
27
+ </section>