coradoc-html 1.1.7
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 +7 -0
- data/LICENSE.txt +21 -0
- data/lib/coradoc/html/base.rb +157 -0
- data/lib/coradoc/html/config.rb +467 -0
- data/lib/coradoc/html/converter_base.rb +177 -0
- data/lib/coradoc/html/converters/admonition.rb +180 -0
- data/lib/coradoc/html/converters/attribute.rb +68 -0
- data/lib/coradoc/html/converters/attribute_reference.rb +60 -0
- data/lib/coradoc/html/converters/audio.rb +165 -0
- data/lib/coradoc/html/converters/base.rb +615 -0
- data/lib/coradoc/html/converters/bibliography.rb +82 -0
- data/lib/coradoc/html/converters/bibliography_entry.rb +108 -0
- data/lib/coradoc/html/converters/block_image.rb +72 -0
- data/lib/coradoc/html/converters/bold.rb +34 -0
- data/lib/coradoc/html/converters/break.rb +32 -0
- data/lib/coradoc/html/converters/comment_block.rb +42 -0
- data/lib/coradoc/html/converters/comment_line.rb +54 -0
- data/lib/coradoc/html/converters/cross_reference.rb +59 -0
- data/lib/coradoc/html/converters/document.rb +108 -0
- data/lib/coradoc/html/converters/example.rb +114 -0
- data/lib/coradoc/html/converters/highlight.rb +34 -0
- data/lib/coradoc/html/converters/include.rb +68 -0
- data/lib/coradoc/html/converters/inline_image.rb +41 -0
- data/lib/coradoc/html/converters/italic.rb +34 -0
- data/lib/coradoc/html/converters/line_break.rb +31 -0
- data/lib/coradoc/html/converters/link.rb +46 -0
- data/lib/coradoc/html/converters/list_item.rb +75 -0
- data/lib/coradoc/html/converters/listing.rb +99 -0
- data/lib/coradoc/html/converters/literal.rb +102 -0
- data/lib/coradoc/html/converters/monospace.rb +34 -0
- data/lib/coradoc/html/converters/open.rb +78 -0
- data/lib/coradoc/html/converters/ordered.rb +53 -0
- data/lib/coradoc/html/converters/paragraph.rb +46 -0
- data/lib/coradoc/html/converters/quote.rb +113 -0
- data/lib/coradoc/html/converters/reviewer_comment.rb +74 -0
- data/lib/coradoc/html/converters/reviewer_note.rb +134 -0
- data/lib/coradoc/html/converters/section.rb +90 -0
- data/lib/coradoc/html/converters/sidebar.rb +113 -0
- data/lib/coradoc/html/converters/source.rb +137 -0
- data/lib/coradoc/html/converters/source_code.rb +16 -0
- data/lib/coradoc/html/converters/span.rb +61 -0
- data/lib/coradoc/html/converters/strikethrough.rb +34 -0
- data/lib/coradoc/html/converters/subscript.rb +34 -0
- data/lib/coradoc/html/converters/superscript.rb +34 -0
- data/lib/coradoc/html/converters/table.rb +85 -0
- data/lib/coradoc/html/converters/table_cell.rb +203 -0
- data/lib/coradoc/html/converters/table_row.rb +45 -0
- data/lib/coradoc/html/converters/template_html_converter.rb +105 -0
- data/lib/coradoc/html/converters/term.rb +58 -0
- data/lib/coradoc/html/converters/text_element.rb +44 -0
- data/lib/coradoc/html/converters/underline.rb +34 -0
- data/lib/coradoc/html/converters/unordered.rb +47 -0
- data/lib/coradoc/html/converters/verse.rb +105 -0
- data/lib/coradoc/html/converters/video.rb +179 -0
- data/lib/coradoc/html/element_mapping.rb +210 -0
- data/lib/coradoc/html/entity.rb +137 -0
- data/lib/coradoc/html/input/cleaner.rb +163 -0
- data/lib/coradoc/html/input/config.rb +79 -0
- data/lib/coradoc/html/input/converters/a.rb +90 -0
- data/lib/coradoc/html/input/converters/aside.rb +23 -0
- data/lib/coradoc/html/input/converters/audio.rb +50 -0
- data/lib/coradoc/html/input/converters/base.rb +116 -0
- data/lib/coradoc/html/input/converters/blockquote.rb +25 -0
- data/lib/coradoc/html/input/converters/br.rb +19 -0
- data/lib/coradoc/html/input/converters/bypass.rb +83 -0
- data/lib/coradoc/html/input/converters/code.rb +25 -0
- data/lib/coradoc/html/input/converters/div.rb +25 -0
- data/lib/coradoc/html/input/converters/dl.rb +106 -0
- data/lib/coradoc/html/input/converters/drop.rb +28 -0
- data/lib/coradoc/html/input/converters/em.rb +23 -0
- data/lib/coradoc/html/input/converters/figure.rb +58 -0
- data/lib/coradoc/html/input/converters/h.rb +76 -0
- data/lib/coradoc/html/input/converters/head.rb +30 -0
- data/lib/coradoc/html/input/converters/hr.rb +20 -0
- data/lib/coradoc/html/input/converters/ignore.rb +22 -0
- data/lib/coradoc/html/input/converters/img.rb +110 -0
- data/lib/coradoc/html/input/converters/li.rb +35 -0
- data/lib/coradoc/html/input/converters/mark.rb +21 -0
- data/lib/coradoc/html/input/converters/markup.rb +107 -0
- data/lib/coradoc/html/input/converters/math.rb +46 -0
- data/lib/coradoc/html/input/converters/ol.rb +46 -0
- data/lib/coradoc/html/input/converters/p.rb +81 -0
- data/lib/coradoc/html/input/converters/pass_through.rb +19 -0
- data/lib/coradoc/html/input/converters/pre.rb +59 -0
- data/lib/coradoc/html/input/converters/q.rb +24 -0
- data/lib/coradoc/html/input/converters/strong.rb +22 -0
- data/lib/coradoc/html/input/converters/sub.rb +40 -0
- data/lib/coradoc/html/input/converters/sup.rb +40 -0
- data/lib/coradoc/html/input/converters/table.rb +64 -0
- data/lib/coradoc/html/input/converters/td.rb +70 -0
- data/lib/coradoc/html/input/converters/text.rb +67 -0
- data/lib/coradoc/html/input/converters/th.rb +20 -0
- data/lib/coradoc/html/input/converters/tr.rb +28 -0
- data/lib/coradoc/html/input/converters/video.rb +53 -0
- data/lib/coradoc/html/input/converters.rb +122 -0
- data/lib/coradoc/html/input/errors.rb +22 -0
- data/lib/coradoc/html/input/html_converter.rb +170 -0
- data/lib/coradoc/html/input/plugin.rb +169 -0
- data/lib/coradoc/html/input/plugins/plateau.rb +229 -0
- data/lib/coradoc/html/input/postprocessor.rb +31 -0
- data/lib/coradoc/html/input.rb +68 -0
- data/lib/coradoc/html/output.rb +95 -0
- data/lib/coradoc/html/renderer.rb +409 -0
- data/lib/coradoc/html/spa.rb +309 -0
- data/lib/coradoc/html/static.rb +293 -0
- data/lib/coradoc/html/template_config.rb +151 -0
- data/lib/coradoc/html/template_helpers.rb +58 -0
- data/lib/coradoc/html/template_locator.rb +114 -0
- data/lib/coradoc/html/theme/base.rb +231 -0
- data/lib/coradoc/html/theme/classic_renderer.rb +390 -0
- data/lib/coradoc/html/theme/modern/components/ui_components.rb +344 -0
- data/lib/coradoc/html/theme/modern/css_generator.rb +311 -0
- data/lib/coradoc/html/theme/modern/javascript_generator.rb +314 -0
- data/lib/coradoc/html/theme/modern/serializers/document_serializer.rb +382 -0
- data/lib/coradoc/html/theme/modern/tailwind_config_builder.rb +164 -0
- data/lib/coradoc/html/theme/modern/vue_template_generator.rb +374 -0
- data/lib/coradoc/html/theme/modern_renderer.rb +250 -0
- data/lib/coradoc/html/theme/registry.rb +153 -0
- data/lib/coradoc/html/theme.rb +13 -0
- data/lib/coradoc/html/transform/from_core_model.rb +32 -0
- data/lib/coradoc/html/transform/to_core_model.rb +39 -0
- data/lib/coradoc/html/version.rb +7 -0
- data/lib/coradoc/html.rb +255 -0
- metadata +264 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Html
|
|
5
|
+
module Theme
|
|
6
|
+
# Modern theme renderer using Vue.js 3 + Tailwind CSS
|
|
7
|
+
#
|
|
8
|
+
# This renderer generates a complete, self-contained HTML5 document
|
|
9
|
+
# with embedded Vue.js components and Tailwind CSS styling.
|
|
10
|
+
# The modern theme features glass morphism aesthetics and interactive
|
|
11
|
+
# UI components.
|
|
12
|
+
#
|
|
13
|
+
# @example Generate modern HTML output
|
|
14
|
+
# html = Coradoc::Output::Html.convert_to_html5(document, theme: :modern)
|
|
15
|
+
class ModernRenderer < Base
|
|
16
|
+
autoload :Serializers, "#{__dir__}/modern/serializers/document_serializer"
|
|
17
|
+
autoload :JavascriptGenerator, "#{__dir__}/modern/javascript_generator"
|
|
18
|
+
autoload :TailwindConfigBuilder, "#{__dir__}/modern/tailwind_config_builder"
|
|
19
|
+
autoload :CSSGenerator, "#{__dir__}/modern/css_generator"
|
|
20
|
+
autoload :UIComponents, "#{__dir__}/modern/components/ui_components"
|
|
21
|
+
|
|
22
|
+
# Register this theme
|
|
23
|
+
Registry.register(:modern, self)
|
|
24
|
+
|
|
25
|
+
# Default configuration for modern theme
|
|
26
|
+
DEFAULT_CONFIG = {
|
|
27
|
+
color_scheme: :glass,
|
|
28
|
+
primary_color: '#6366f1', # Indigo-500
|
|
29
|
+
accent_color: '#8b5cf6', # Violet-500
|
|
30
|
+
max_width: '1200px',
|
|
31
|
+
content_width: '65ch',
|
|
32
|
+
sidebar_width: '280px',
|
|
33
|
+
theme_toggle: true,
|
|
34
|
+
reading_progress: true,
|
|
35
|
+
back_to_top: true,
|
|
36
|
+
toc_sticky: true,
|
|
37
|
+
copy_code_buttons: true,
|
|
38
|
+
enable_animations: true,
|
|
39
|
+
animation_duration: '300ms',
|
|
40
|
+
lazy_load_images: true
|
|
41
|
+
}.freeze
|
|
42
|
+
|
|
43
|
+
# Get template directories (from options or global config)
|
|
44
|
+
#
|
|
45
|
+
# @return [Array<String>]
|
|
46
|
+
def template_dirs
|
|
47
|
+
@options[:template_dirs] || global_template_dirs
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Check if custom templates are configured and available
|
|
51
|
+
#
|
|
52
|
+
# @return [Boolean]
|
|
53
|
+
def use_custom_templates?
|
|
54
|
+
dirs = template_dirs
|
|
55
|
+
return false if dirs.empty?
|
|
56
|
+
|
|
57
|
+
dirs.any? { |dir| File.directory?(dir) }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Supported features for modern theme
|
|
61
|
+
#
|
|
62
|
+
# @return [Array<Symbol>] Supported features
|
|
63
|
+
def supported_features
|
|
64
|
+
%i[
|
|
65
|
+
dark_mode
|
|
66
|
+
theme_toggle
|
|
67
|
+
interactive_toc
|
|
68
|
+
reading_progress
|
|
69
|
+
back_to_top
|
|
70
|
+
copy_code_buttons
|
|
71
|
+
lazy_loading
|
|
72
|
+
animations
|
|
73
|
+
glass_morphism
|
|
74
|
+
]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Render document to HTML
|
|
78
|
+
#
|
|
79
|
+
# Generates a complete HTML5 document with Vue.js application.
|
|
80
|
+
#
|
|
81
|
+
# @return [String] Complete HTML5 document
|
|
82
|
+
def render
|
|
83
|
+
render_html5
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Render complete HTML5 document
|
|
87
|
+
#
|
|
88
|
+
# @return [String] Complete HTML5 document
|
|
89
|
+
def render_html5
|
|
90
|
+
# Merge user options with defaults
|
|
91
|
+
config = DEFAULT_CONFIG.merge(@options[:modern] || {})
|
|
92
|
+
|
|
93
|
+
# Serialize document to Vue-compatible format
|
|
94
|
+
document_data = serialize_document
|
|
95
|
+
|
|
96
|
+
# Generate Vue application code
|
|
97
|
+
vue_app = generate_vue_app(document_data, config)
|
|
98
|
+
|
|
99
|
+
# Generate Tailwind configuration
|
|
100
|
+
tailwind_config = generate_tailwind_config(config)
|
|
101
|
+
|
|
102
|
+
# Generate custom CSS
|
|
103
|
+
custom_css = generate_custom_css(config)
|
|
104
|
+
|
|
105
|
+
# Build complete HTML document
|
|
106
|
+
build_html_document(vue_app, tailwind_config, custom_css, config)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
# Get global template directories from configuration
|
|
112
|
+
def global_template_dirs
|
|
113
|
+
Coradoc::Html.configuration.template_dirs.map(&:to_s)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Serialize document to Vue-compatible data structure
|
|
117
|
+
#
|
|
118
|
+
# @return [Hash] Serialized document data
|
|
119
|
+
def serialize_document
|
|
120
|
+
Serializers::DocumentSerializer.serialize(@document)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Generate Vue application code
|
|
124
|
+
#
|
|
125
|
+
# @param document_data [Hash] Serialized document data
|
|
126
|
+
# @param config [Hash] Theme configuration
|
|
127
|
+
# @return [String] Vue application JavaScript
|
|
128
|
+
def generate_vue_app(document_data, config)
|
|
129
|
+
JavascriptGenerator.generate(document_data, config)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Generate Tailwind CSS configuration
|
|
133
|
+
#
|
|
134
|
+
# @param config [Hash] Theme configuration
|
|
135
|
+
# @return [String] Tailwind configuration script
|
|
136
|
+
def generate_tailwind_config(config)
|
|
137
|
+
TailwindConfigBuilder.build(config)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Generate custom CSS for glass morphism and special effects
|
|
141
|
+
#
|
|
142
|
+
# @param config [Hash] Theme configuration
|
|
143
|
+
# @return [String] Custom CSS
|
|
144
|
+
def generate_custom_css(config)
|
|
145
|
+
UIComponents.enhanced_css(config)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Build complete HTML document
|
|
149
|
+
#
|
|
150
|
+
# @param vue_app [String] Vue application code
|
|
151
|
+
# @param tailwind_config [String] Tailwind configuration
|
|
152
|
+
# @param custom_css [String] Custom CSS
|
|
153
|
+
# @param config [Hash] Theme configuration
|
|
154
|
+
# @return [String] Complete HTML5 document
|
|
155
|
+
def build_html_document(vue_app, tailwind_config, custom_css, config)
|
|
156
|
+
lang = @options[:lang] || 'en'
|
|
157
|
+
title = extract_document_title
|
|
158
|
+
|
|
159
|
+
# Meta tags
|
|
160
|
+
meta_tags = build_meta_tags(config)
|
|
161
|
+
|
|
162
|
+
# Open Graph tags if enabled
|
|
163
|
+
og_tags = config[:open_graph] ? build_open_graph_tags : ''
|
|
164
|
+
|
|
165
|
+
# Vue and Tailwind CDN links
|
|
166
|
+
cdn_links = build_cdn_links
|
|
167
|
+
|
|
168
|
+
<<~HTML
|
|
169
|
+
<!DOCTYPE html>
|
|
170
|
+
<html lang="#{lang}" class="#{config[:color_scheme]}">
|
|
171
|
+
<head>
|
|
172
|
+
<meta charset="UTF-8">
|
|
173
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
174
|
+
#{meta_tags}
|
|
175
|
+
<title>#{escape_html(title)}</title>
|
|
176
|
+
#{og_tags}
|
|
177
|
+
#{cdn_links}
|
|
178
|
+
<script>#{tailwind_config}</script>
|
|
179
|
+
<style>#{custom_css}</style>
|
|
180
|
+
</head>
|
|
181
|
+
<body class="bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800 min-h-screen transition-colors duration-300">
|
|
182
|
+
<div id="app"></div>
|
|
183
|
+
<script>#{vue_app}</script>
|
|
184
|
+
</body>
|
|
185
|
+
</html>
|
|
186
|
+
HTML
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Build meta tags
|
|
190
|
+
#
|
|
191
|
+
# @param config [Hash] Theme configuration
|
|
192
|
+
# @return [String] Meta tags HTML
|
|
193
|
+
def build_meta_tags(config)
|
|
194
|
+
tags = []
|
|
195
|
+
|
|
196
|
+
# Author
|
|
197
|
+
tags << %(<meta name="author" content="#{escape_attr(@options[:author])}">) if @options[:author]
|
|
198
|
+
|
|
199
|
+
# Description
|
|
200
|
+
description = config[:meta_description] || @options[:description]
|
|
201
|
+
tags << %(<meta name="description" content="#{escape_attr(description)}">) if description
|
|
202
|
+
|
|
203
|
+
# Keywords
|
|
204
|
+
keywords = config[:meta_keywords] || @options[:keywords]
|
|
205
|
+
tags << %(<meta name="keywords" content="#{escape_attr(keywords)}">) if keywords
|
|
206
|
+
|
|
207
|
+
# Generator
|
|
208
|
+
tags << %{<meta name="generator" content="Coradoc #{Coradoc::VERSION} (Modern Theme)">}
|
|
209
|
+
|
|
210
|
+
# Timestamp
|
|
211
|
+
tags << %(<meta name="generated" content="#{Time.now.utc.iso8601}">)
|
|
212
|
+
|
|
213
|
+
# Custom meta tags
|
|
214
|
+
if @options[:meta_tags].is_a?(Hash)
|
|
215
|
+
@options[:meta_tags].each do |name, content|
|
|
216
|
+
tags << %(<meta name="#{escape_attr(name)}" content="#{escape_attr(content)}">)
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
tags.join("\n ")
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Build Open Graph tags
|
|
224
|
+
#
|
|
225
|
+
# @return [String] Open Graph tags HTML
|
|
226
|
+
def build_open_graph_tags
|
|
227
|
+
title = extract_document_title
|
|
228
|
+
<<~HTML
|
|
229
|
+
<meta property="og:title" content="#{escape_html(title)}">
|
|
230
|
+
<meta property="og:type" content="article">
|
|
231
|
+
<meta property="og:generator" content="Coradoc #{Coradoc::VERSION}">
|
|
232
|
+
HTML
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Build CDN links for Vue and Tailwind
|
|
236
|
+
#
|
|
237
|
+
# @return [String] CDN link tags
|
|
238
|
+
def build_cdn_links
|
|
239
|
+
<<~HTML
|
|
240
|
+
<!-- Vue.js 3 (with template compiler for runtime compilation) -->
|
|
241
|
+
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
|
242
|
+
|
|
243
|
+
<!-- Tailwind CSS 3.4 -->
|
|
244
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
245
|
+
HTML
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Html
|
|
5
|
+
module Theme
|
|
6
|
+
# Theme registry for managing and retrieving theme renderers
|
|
7
|
+
#
|
|
8
|
+
# The registry maintains a collection of available themes and provides
|
|
9
|
+
# methods for registration, lookup, and validation.
|
|
10
|
+
#
|
|
11
|
+
# @example Registering a custom theme
|
|
12
|
+
# class MyCustomTheme < Coradoc::Html::Theme::Base
|
|
13
|
+
# def render
|
|
14
|
+
# "<h1>Custom HTML</h1>"
|
|
15
|
+
# end
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# Coradoc::Html::Theme::Registry.register(:my_custom, MyCustomTheme)
|
|
19
|
+
#
|
|
20
|
+
# @example Using a theme
|
|
21
|
+
# renderer = Coradoc::Html::Theme::Registry.find(:my_custom)
|
|
22
|
+
# renderer.new(document, options).render
|
|
23
|
+
class Registry
|
|
24
|
+
class << self
|
|
25
|
+
# Registered themes mapping
|
|
26
|
+
#
|
|
27
|
+
# @return [Hash] Theme name to renderer class mapping
|
|
28
|
+
def themes
|
|
29
|
+
@themes ||= {}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Register a theme renderer
|
|
33
|
+
#
|
|
34
|
+
# @param name [Symbol] Theme name (e.g., :classic, :modern)
|
|
35
|
+
# @param renderer_class [Class] Theme renderer class
|
|
36
|
+
# @raise [ArgumentError] if renderer_class is not a Theme::Base subclass
|
|
37
|
+
#
|
|
38
|
+
# @example Register a theme
|
|
39
|
+
# Registry.register(:my_theme, MyThemeRenderer)
|
|
40
|
+
def register(name, renderer_class)
|
|
41
|
+
unless renderer_class.is_a?(Class) &&
|
|
42
|
+
renderer_class <= Coradoc::Html::Theme::Base
|
|
43
|
+
raise ArgumentError,
|
|
44
|
+
'Theme renderer must be a subclass of Coradoc::Html::Theme::Base, ' \
|
|
45
|
+
"got: #{renderer_class}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
themes[name] = renderer_class
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Find a theme renderer by name
|
|
52
|
+
#
|
|
53
|
+
# @param name [Symbol] Theme name
|
|
54
|
+
# @return [Class, nil] Theme renderer class or nil if not found
|
|
55
|
+
#
|
|
56
|
+
# @example Find a theme
|
|
57
|
+
# renderer = Registry.find(:modern)
|
|
58
|
+
def find(name)
|
|
59
|
+
themes[name]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Check if a theme is registered
|
|
63
|
+
#
|
|
64
|
+
# @param name [Symbol] Theme name
|
|
65
|
+
# @return [Boolean] true if theme is registered
|
|
66
|
+
#
|
|
67
|
+
# @example Check theme existence
|
|
68
|
+
# Registry.registered?(:modern) # => true
|
|
69
|
+
def registered?(name)
|
|
70
|
+
themes.key?(name)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Get all registered theme names
|
|
74
|
+
#
|
|
75
|
+
# @return [Array<Symbol>] List of registered theme names
|
|
76
|
+
#
|
|
77
|
+
# @example List all themes
|
|
78
|
+
# Registry.all_theme_names # => [:classic, :modern]
|
|
79
|
+
def all_theme_names
|
|
80
|
+
themes.keys.sort
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Get default theme name
|
|
84
|
+
#
|
|
85
|
+
# @return [Symbol] Default theme name
|
|
86
|
+
def default_theme
|
|
87
|
+
:classic
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Resolve theme from options
|
|
91
|
+
#
|
|
92
|
+
# Returns the theme renderer class based on the provided options.
|
|
93
|
+
# Falls back to default theme if not specified or if theme not found.
|
|
94
|
+
#
|
|
95
|
+
# @param options [Hash] Rendering options
|
|
96
|
+
# @return [Class] Theme renderer class
|
|
97
|
+
#
|
|
98
|
+
# @example Resolve theme from options
|
|
99
|
+
# renderer = Registry.resolve_from_options(theme: :modern)
|
|
100
|
+
def resolve_from_options(options = {})
|
|
101
|
+
theme_name = options.fetch(:theme, default_theme)
|
|
102
|
+
|
|
103
|
+
renderer_class = find(theme_name)
|
|
104
|
+
return renderer_class if renderer_class
|
|
105
|
+
|
|
106
|
+
# Theme not found, fall back to default
|
|
107
|
+
Coradoc::Logger.warn(
|
|
108
|
+
"Theme '#{theme_name}' not found, falling back to '#{default_theme}'"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
find(default_theme) || raise("Default theme '#{default_theme}' not registered")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Auto-register a theme class
|
|
115
|
+
#
|
|
116
|
+
# This method is called by theme classes when they are loaded.
|
|
117
|
+
# It extracts the theme name from the class name and registers it.
|
|
118
|
+
#
|
|
119
|
+
# @param renderer_class [Class] Theme renderer class
|
|
120
|
+
#
|
|
121
|
+
# @example Auto-register from within a theme class
|
|
122
|
+
# class ModernTheme < Coradoc::Output::Html::Theme::Base
|
|
123
|
+
# Coradoc::Output::Html::Theme::Registry.auto_register(self)
|
|
124
|
+
# end
|
|
125
|
+
def auto_register(renderer_class)
|
|
126
|
+
# Extract theme name from class name
|
|
127
|
+
# e.g., ModernRenderer -> :modern, ClassicRenderer -> :classic
|
|
128
|
+
class_name = renderer_class.name.split('::').last
|
|
129
|
+
|
|
130
|
+
# Remove "Renderer" suffix if present
|
|
131
|
+
theme_name = class_name.sub(/Renderer$/, '')
|
|
132
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
133
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
134
|
+
.downcase
|
|
135
|
+
.to_sym
|
|
136
|
+
|
|
137
|
+
register(theme_name, renderer_class)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Clear all registered themes (mainly for testing)
|
|
141
|
+
#
|
|
142
|
+
# @return [void]
|
|
143
|
+
#
|
|
144
|
+
# @example Clear registry
|
|
145
|
+
# Registry.clear
|
|
146
|
+
def clear
|
|
147
|
+
@themes = {}
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Html
|
|
5
|
+
module Theme
|
|
6
|
+
# Autoload Theme components
|
|
7
|
+
autoload :Base, 'coradoc/html/theme/base'
|
|
8
|
+
autoload :Registry, 'coradoc/html/theme/registry'
|
|
9
|
+
autoload :ClassicRenderer, 'coradoc/html/theme/classic_renderer'
|
|
10
|
+
autoload :ModernRenderer, 'coradoc/html/theme/modern_renderer'
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Html
|
|
5
|
+
module Transform
|
|
6
|
+
# Transforms CoreModel models to HTML output
|
|
7
|
+
#
|
|
8
|
+
# This transformer converts CoreModel to structures suitable for
|
|
9
|
+
# HTML rendering. Note: The HTML converters already support CoreModel
|
|
10
|
+
# directly, so this transformer primarily passes through the CoreModel.
|
|
11
|
+
class FromCoreModel
|
|
12
|
+
class << self
|
|
13
|
+
# Transform a CoreModel to HTML-ready structure
|
|
14
|
+
#
|
|
15
|
+
# @param model [Coradoc::CoreModel::Base] CoreModel to transform
|
|
16
|
+
# @return [Object] HTML-ready structure
|
|
17
|
+
def transform(model)
|
|
18
|
+
case model
|
|
19
|
+
when Coradoc::CoreModel::Base
|
|
20
|
+
# HTML converters already support CoreModel directly
|
|
21
|
+
model
|
|
22
|
+
when Array
|
|
23
|
+
model.map { |item| transform(item) }
|
|
24
|
+
else
|
|
25
|
+
model
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'coradoc/core_model'
|
|
4
|
+
|
|
5
|
+
module Coradoc
|
|
6
|
+
module Html
|
|
7
|
+
module Transform
|
|
8
|
+
# Transforms HTML input models to CoreModel equivalents
|
|
9
|
+
#
|
|
10
|
+
# HTML input converters now produce CoreModel directly, so this transformer
|
|
11
|
+
# is largely a pass-through that ensures the model is CoreModel.
|
|
12
|
+
class ToCoreModel
|
|
13
|
+
class << self
|
|
14
|
+
# Transform an HTML input model to CoreModel
|
|
15
|
+
#
|
|
16
|
+
# @param model [Object] HTML input model to transform
|
|
17
|
+
# @return [Coradoc::CoreModel::Base] CoreModel equivalent
|
|
18
|
+
def transform(model)
|
|
19
|
+
# HTML input now produces CoreModel directly
|
|
20
|
+
transform_direct(model)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def transform_direct(model)
|
|
26
|
+
case model
|
|
27
|
+
when Coradoc::CoreModel::Base
|
|
28
|
+
model
|
|
29
|
+
when Array
|
|
30
|
+
model.map { |item| transform(item) }
|
|
31
|
+
else
|
|
32
|
+
model
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|