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,344 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Html
|
|
5
|
+
module Theme
|
|
6
|
+
class ModernRenderer
|
|
7
|
+
# UI component templates for interactive elements
|
|
8
|
+
module UIComponents
|
|
9
|
+
class << self
|
|
10
|
+
# Generate UI components HTML
|
|
11
|
+
#
|
|
12
|
+
# @param config [Hash] Theme configuration
|
|
13
|
+
# @return [String] UI components HTML
|
|
14
|
+
def generate_html(config)
|
|
15
|
+
<<~HTML
|
|
16
|
+
<!-- Reading Progress Bar -->
|
|
17
|
+
#{reading_progress_html(config)}
|
|
18
|
+
|
|
19
|
+
<!-- Theme Toggle Button -->
|
|
20
|
+
#{theme_toggle_html(config)}
|
|
21
|
+
|
|
22
|
+
<!-- Back to Top Button -->
|
|
23
|
+
#{back_to_top_html(config)}
|
|
24
|
+
HTML
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Reading progress bar HTML
|
|
28
|
+
#
|
|
29
|
+
# @param config [Hash] Theme configuration
|
|
30
|
+
# @return [String] Reading progress bar HTML
|
|
31
|
+
def reading_progress_html(config)
|
|
32
|
+
return '' unless config[:reading_progress]
|
|
33
|
+
|
|
34
|
+
<<~HTML
|
|
35
|
+
<div id="reading-progress" :style="{ width: scrollProgress + '%' }"></div>
|
|
36
|
+
HTML
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Theme toggle button HTML
|
|
40
|
+
#
|
|
41
|
+
# @param config [Hash] Theme configuration
|
|
42
|
+
# @return [String] Theme toggle button HTML
|
|
43
|
+
def theme_toggle_html(config)
|
|
44
|
+
return '' unless config[:theme_toggle]
|
|
45
|
+
|
|
46
|
+
<<~HTML
|
|
47
|
+
<button
|
|
48
|
+
id="theme-toggle"
|
|
49
|
+
@click="toggleTheme"
|
|
50
|
+
:title="isDark ? 'Switch to light mode' : 'Switch to dark mode'"
|
|
51
|
+
aria-label="Toggle dark mode"
|
|
52
|
+
class="fixed top-4 right-4 p-2 rounded-full bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm border border-gray-200 dark:border-gray-700 shadow-lg hover:shadow-xl transition-all hover:scale-110 z-50"
|
|
53
|
+
>
|
|
54
|
+
<svg v-if="!isDark" class="w-5 h-5 text-yellow-500" fill="currentColor" viewBox="0 0 20 20">
|
|
55
|
+
<path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h1a1 1 0 100 2h-1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd" />
|
|
56
|
+
</svg>
|
|
57
|
+
<svg v-else class="w-5 h-5 text-indigo-400" fill="currentColor" viewBox="0 0 20 20">
|
|
58
|
+
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
|
|
59
|
+
</svg>
|
|
60
|
+
</button>
|
|
61
|
+
HTML
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Back to top button HTML
|
|
65
|
+
#
|
|
66
|
+
# @param config [Hash] Theme configuration
|
|
67
|
+
# @return [String] Back to top button HTML
|
|
68
|
+
def back_to_top_html(config)
|
|
69
|
+
return '' unless config[:back_to_top]
|
|
70
|
+
|
|
71
|
+
<<~HTML
|
|
72
|
+
<button
|
|
73
|
+
id="back-to-top"
|
|
74
|
+
v-show="showBackToTop"
|
|
75
|
+
@click="scrollToTop"
|
|
76
|
+
title="Back to top"
|
|
77
|
+
aria-label="Back to top"
|
|
78
|
+
class="fixed bottom-6 right-6 p-3 rounded-full bg-gradient-to-r from-primary-600 to-primary-500 text-white shadow-lg hover:shadow-xl transition-all hover:scale-110 z-50"
|
|
79
|
+
:class="{ 'opacity-0 pointer-events-none translate-y-2': !showBackToTop }"
|
|
80
|
+
>
|
|
81
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
82
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18" />
|
|
83
|
+
</svg>
|
|
84
|
+
</button>
|
|
85
|
+
HTML
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Enhanced document template with UI components
|
|
89
|
+
#
|
|
90
|
+
# @return [String] Enhanced document template
|
|
91
|
+
def enhanced_document_template(_config)
|
|
92
|
+
<<~VUE
|
|
93
|
+
<div class="min-h-screen bg-gradient-to-br from-slate-50 via-white to-slate-100 dark:from-gray-900 dark:via-gray-800 dark:to-gray-900 transition-colors duration-300">
|
|
94
|
+
<!-- Reading Progress Bar -->
|
|
95
|
+
<div v-if="config.reading_progress" class="reading-progress-bar" :style="{ width: scrollProgress + '%' }"></div>
|
|
96
|
+
|
|
97
|
+
<!-- Theme Toggle Button -->
|
|
98
|
+
<button
|
|
99
|
+
v-if="config.theme_toggle"
|
|
100
|
+
@click="toggleTheme"
|
|
101
|
+
class="theme-toggle-btn"
|
|
102
|
+
:title="isDark ? 'Switch to light mode' : 'Switch to dark mode'"
|
|
103
|
+
>
|
|
104
|
+
<svg v-if="!isDark" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
105
|
+
<path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h1a1 1 0 100 2h-1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd" />
|
|
106
|
+
</svg>
|
|
107
|
+
<svg v-else class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
108
|
+
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
|
|
109
|
+
</svg>
|
|
110
|
+
</button>
|
|
111
|
+
|
|
112
|
+
<!-- Back to Top Button -->
|
|
113
|
+
<button
|
|
114
|
+
v-if="config.back_to_top"
|
|
115
|
+
v-show="showBackToTop"
|
|
116
|
+
@click="scrollToTop"
|
|
117
|
+
class="back-to-top-btn"
|
|
118
|
+
title="Back to top"
|
|
119
|
+
>
|
|
120
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
121
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18" />
|
|
122
|
+
</svg>
|
|
123
|
+
</button>
|
|
124
|
+
|
|
125
|
+
<!-- Main Document Container -->
|
|
126
|
+
<div class="document-container mx-auto px-4 py-8 max-w-7xl">
|
|
127
|
+
<div class="flex gap-8">
|
|
128
|
+
<!-- TOC Sidebar -->
|
|
129
|
+
<aside v-if="config.toc_sticky && showToc" class="toc-sidebar" :class="{ 'collapsed': tocCollapsed }">
|
|
130
|
+
<nav class="toc-nav sticky top-4">
|
|
131
|
+
<h3 class="toc-title text-lg font-semibold mb-4 text-gray-900 dark:text-white">Contents</h3>
|
|
132
|
+
<ul class="toc-list space-y-1">
|
|
133
|
+
<li
|
|
134
|
+
v-for="item in tocItems"
|
|
135
|
+
:key="item.id"
|
|
136
|
+
@click="scrollToSection(item.id)"
|
|
137
|
+
class="toc-item p-2 rounded-lg cursor-pointer transition-all"
|
|
138
|
+
:class="{ 'active': activeSection === item.id }"
|
|
139
|
+
:style="{ paddingLeft: (item.level * 0.75 + 1) + 'rem' }"
|
|
140
|
+
>
|
|
141
|
+
{{ item.title }}
|
|
142
|
+
</li>
|
|
143
|
+
</ul>
|
|
144
|
+
</nav>
|
|
145
|
+
</aside>
|
|
146
|
+
|
|
147
|
+
<!-- Main Content -->
|
|
148
|
+
<main class="flex-1 min-w-0">
|
|
149
|
+
<article class="prose prose-lg dark:prose-invert max-w-none
|
|
150
|
+
prose-headings:text-gray-900 dark:prose-headings:text-white
|
|
151
|
+
prose-p:text-gray-700 dark:prose-p:text-gray-300
|
|
152
|
+
prose-a:text-primary-600 dark:prose-a:text-primary-400
|
|
153
|
+
prose-strong:text-gray-900 dark:prose-strong:text-white
|
|
154
|
+
prose-code:text-pink-600 dark:prose-code:text-pink-400
|
|
155
|
+
prose-pre:bg-gray-100 dark:prose-pre:bg-gray-800">
|
|
156
|
+
<template v-for="(section, index) in document.sections" :key="section.id || index">
|
|
157
|
+
<component :is="'section-' + section.type" :data="section" v-if="section.type === 'section'" />
|
|
158
|
+
<component :is="'element-' + section.type" :data="section" v-else />
|
|
159
|
+
</template>
|
|
160
|
+
</article>
|
|
161
|
+
</main>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
VUE
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Generate complete CSS with enhanced styles
|
|
169
|
+
#
|
|
170
|
+
# @param config [Hash] Theme configuration
|
|
171
|
+
# @return [String] Enhanced CSS
|
|
172
|
+
def enhanced_css(config)
|
|
173
|
+
base_css = CSSGenerator.generate(config)
|
|
174
|
+
|
|
175
|
+
base_css + <<~CSS
|
|
176
|
+
|
|
177
|
+
/* Reading Progress Bar */
|
|
178
|
+
.reading-progress-bar {
|
|
179
|
+
position: fixed;
|
|
180
|
+
top: 0;
|
|
181
|
+
left: 0;
|
|
182
|
+
height: 3px;
|
|
183
|
+
background: linear-gradient(90deg, #{config[:primary_color]}, #{config[:accent_color]});
|
|
184
|
+
transition: width 0.1s ease-out;
|
|
185
|
+
z-index: 9999;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Theme Toggle Button */
|
|
189
|
+
.theme-toggle-btn {
|
|
190
|
+
position: fixed;
|
|
191
|
+
top: 1.5rem;
|
|
192
|
+
right: 1.5rem;
|
|
193
|
+
width: 2.75rem;
|
|
194
|
+
height: 2.75rem;
|
|
195
|
+
border-radius: 9999px;
|
|
196
|
+
background: rgba(255, 255, 255, 0.9);
|
|
197
|
+
backdrop-filter: blur(10px);
|
|
198
|
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
199
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
200
|
+
display: flex;
|
|
201
|
+
align-items: center;
|
|
202
|
+
justify-content: center;
|
|
203
|
+
cursor: pointer;
|
|
204
|
+
transition: all 0.3s ease;
|
|
205
|
+
z-index: 1000;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.theme-toggle-btn:hover {
|
|
209
|
+
transform: scale(1.1);
|
|
210
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.dark .theme-toggle-btn {
|
|
214
|
+
background: rgba(0, 0, 0, 0.5);
|
|
215
|
+
border-color: rgba(255, 255, 255, 0.1);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/* Back to Top Button */
|
|
219
|
+
.back-to-top-btn {
|
|
220
|
+
position: fixed;
|
|
221
|
+
bottom: 1.5rem;
|
|
222
|
+
right: 1.5rem;
|
|
223
|
+
width: 3rem;
|
|
224
|
+
height: 3rem;
|
|
225
|
+
border-radius: 9999px;
|
|
226
|
+
background: linear-gradient(135deg, #{config[:primary_color]}, #{config[:accent_color]});
|
|
227
|
+
color: white;
|
|
228
|
+
border: none;
|
|
229
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
230
|
+
display: flex;
|
|
231
|
+
align-items: center;
|
|
232
|
+
justify-content: center;
|
|
233
|
+
cursor: pointer;
|
|
234
|
+
transition: all 0.3s ease;
|
|
235
|
+
opacity: 1;
|
|
236
|
+
transform: translateY(0);
|
|
237
|
+
z-index: 1000;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.back-to-top-btn:hover {
|
|
241
|
+
transform: translateY(-2px);
|
|
242
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.back-to-top-btn.opacity-0 {
|
|
246
|
+
opacity: 0;
|
|
247
|
+
pointer-events: none;
|
|
248
|
+
transform: translateY(10px);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/* TOC Sidebar */
|
|
252
|
+
.toc-sidebar {
|
|
253
|
+
position: sticky;
|
|
254
|
+
top: 2rem;
|
|
255
|
+
width: #{config[:sidebar_width] || '280px'};
|
|
256
|
+
max-height: calc(100vh - 4rem);
|
|
257
|
+
overflow-y: auto;
|
|
258
|
+
padding: 1.5rem;
|
|
259
|
+
background: rgba(255, 255, 255, 0.8);
|
|
260
|
+
backdrop-filter: blur(10px);
|
|
261
|
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
262
|
+
border-radius: 0.75rem;
|
|
263
|
+
transition: all 0.3s ease;
|
|
264
|
+
z-index: 100;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.dark .toc-sidebar {
|
|
268
|
+
background: rgba(0, 0, 0, 0.5);
|
|
269
|
+
border-color: rgba(255, 255, 255, 0.1);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.toc-sidebar.collapsed {
|
|
273
|
+
transform: translateX(-120%);
|
|
274
|
+
opacity: 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.toc-item {
|
|
278
|
+
display: block;
|
|
279
|
+
color: #6b7280;
|
|
280
|
+
transition: all 0.2s ease;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.dark .toc-item {
|
|
284
|
+
color: #9ca3af;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.toc-item:hover {
|
|
288
|
+
background: rgba(99, 102, 241, 0.1);
|
|
289
|
+
color: #{config[:primary_color]};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.toc-item.active {
|
|
293
|
+
background: linear-gradient(135deg, rgba(99, 102, 241, 0.15), rgba(139, 92, 246, 0.15));
|
|
294
|
+
color: #{config[:primary_color]};
|
|
295
|
+
font-weight: 600;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/* Document Container */
|
|
299
|
+
.document-container {
|
|
300
|
+
background: transparent;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/* Smooth animations */
|
|
304
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
305
|
+
.toc-item {
|
|
306
|
+
animation: slideIn 0.3s ease-out;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
@keyframes slideIn {
|
|
310
|
+
from {
|
|
311
|
+
opacity: 0;
|
|
312
|
+
transform: translateX(-10px);
|
|
313
|
+
}
|
|
314
|
+
to {
|
|
315
|
+
opacity: 1;
|
|
316
|
+
transform: translateX(0);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/* Responsive */
|
|
322
|
+
@media (max-width: 1024px) {
|
|
323
|
+
.toc-sidebar {
|
|
324
|
+
position: fixed;
|
|
325
|
+
left: 0;
|
|
326
|
+
top: 0;
|
|
327
|
+
height: 100vh;
|
|
328
|
+
max-height: 100vh;
|
|
329
|
+
z-index: 200;
|
|
330
|
+
transform: translateX(-100%);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.toc-sidebar:not(.collapsed) {
|
|
334
|
+
transform: translateX(0);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
CSS
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
end
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Html
|
|
5
|
+
module Theme
|
|
6
|
+
class ModernRenderer
|
|
7
|
+
# Generate custom CSS for glass morphism and special effects
|
|
8
|
+
module CSSGenerator
|
|
9
|
+
class << self
|
|
10
|
+
# Generate custom CSS
|
|
11
|
+
#
|
|
12
|
+
# @param config [Hash] Theme configuration
|
|
13
|
+
# @return [String] CSS content
|
|
14
|
+
def generate(config)
|
|
15
|
+
<<~CSS
|
|
16
|
+
/* Glass Morphism Effects */
|
|
17
|
+
.glass {
|
|
18
|
+
background: rgba(255, 255, 255, 0.1);
|
|
19
|
+
backdrop-filter: blur(10px);
|
|
20
|
+
-webkit-backdrop-filter: blur(10px);
|
|
21
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.glass-dark {
|
|
25
|
+
background: rgba(0, 0, 0, 0.2);
|
|
26
|
+
backdrop-filter: blur(10px);
|
|
27
|
+
-webkit-backdrop-filter: blur(10px);
|
|
28
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Custom scrollbar */
|
|
32
|
+
::-webkit-scrollbar {
|
|
33
|
+
width: 8px;
|
|
34
|
+
height: 8px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
::-webkit-scrollbar-track {
|
|
38
|
+
background: rgba(0, 0, 0, 0.05);
|
|
39
|
+
border-radius: 4px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
::-webkit-scrollbar-thumb {
|
|
43
|
+
background: rgba(99, 102, 241, 0.5);
|
|
44
|
+
border-radius: 4px;
|
|
45
|
+
transition: background 0.3s;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
::-webkit-scrollbar-thumb:hover {
|
|
49
|
+
background: rgba(99, 102, 241, 0.7);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.dark ::-webkit-scrollbar-track {
|
|
53
|
+
background: rgba(255, 255, 255, 0.05);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.dark ::-webkit-scrollbar-thumb {
|
|
57
|
+
background: rgba(139, 92, 246, 0.5);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.dark ::-webkit-scrollbar-thumb:hover {
|
|
61
|
+
background: rgba(139, 92, 246, 0.7);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Reading progress bar */
|
|
65
|
+
#reading-progress {
|
|
66
|
+
position: fixed;
|
|
67
|
+
top: 0;
|
|
68
|
+
left: 0;
|
|
69
|
+
height: 3px;
|
|
70
|
+
background: linear-gradient(90deg, #{config[:primary_color]}, #{config[:accent_color]});
|
|
71
|
+
transition: width 0.1s ease-out;
|
|
72
|
+
z-index: 9999;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Back to top button */
|
|
76
|
+
#back-to-top {
|
|
77
|
+
position: fixed;
|
|
78
|
+
bottom: 2rem;
|
|
79
|
+
right: 2rem;
|
|
80
|
+
width: 3rem;
|
|
81
|
+
height: 3rem;
|
|
82
|
+
border-radius: 50%;
|
|
83
|
+
background: #{config[:primary_color]};
|
|
84
|
+
color: white;
|
|
85
|
+
border: none;
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
91
|
+
transition: all 0.3s ease;
|
|
92
|
+
z-index: 1000;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#back-to-top:hover {
|
|
96
|
+
transform: translateY(-2px);
|
|
97
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
#back-to-top.hidden {
|
|
101
|
+
opacity: 0;
|
|
102
|
+
pointer-events: none;
|
|
103
|
+
transform: translateY(10px);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Theme toggle button */
|
|
107
|
+
#theme-toggle {
|
|
108
|
+
position: fixed;
|
|
109
|
+
top: 1rem;
|
|
110
|
+
right: 1rem;
|
|
111
|
+
padding: 0.5rem;
|
|
112
|
+
border-radius: 0.5rem;
|
|
113
|
+
background: rgba(255, 255, 255, 0.9);
|
|
114
|
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
115
|
+
cursor: pointer;
|
|
116
|
+
transition: all 0.3s ease;
|
|
117
|
+
z-index: 1000;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.dark #theme-toggle {
|
|
121
|
+
background: rgba(0, 0, 0, 0.5);
|
|
122
|
+
border-color: rgba(255, 255, 255, 0.1);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#theme-toggle:hover {
|
|
126
|
+
transform: scale(1.05);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* Table of contents */
|
|
130
|
+
.toc-sidebar {
|
|
131
|
+
position: fixed;
|
|
132
|
+
top: 0;
|
|
133
|
+
left: 0;
|
|
134
|
+
height: 100vh;
|
|
135
|
+
width: #{config[:sidebar_width] || '280px'};
|
|
136
|
+
padding: 2rem 1rem;
|
|
137
|
+
overflow-y: auto;
|
|
138
|
+
background: rgba(255, 255, 255, 0.95);
|
|
139
|
+
backdrop-filter: blur(10px);
|
|
140
|
+
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
|
141
|
+
transition: transform 0.3s ease;
|
|
142
|
+
z-index: 100;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.dark .toc-sidebar {
|
|
146
|
+
background: rgba(0, 0, 0, 0.5);
|
|
147
|
+
border-right-color: rgba(255, 255, 255, 0.1);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.toc-sidebar.collapsed {
|
|
151
|
+
transform: translateX(-100%);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.toc-item {
|
|
155
|
+
padding: 0.5rem;
|
|
156
|
+
border-radius: 0.375rem;
|
|
157
|
+
cursor: pointer;
|
|
158
|
+
transition: all 0.2s ease;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.toc-item:hover {
|
|
162
|
+
background: rgba(99, 102, 241, 0.1);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.toc-item.active {
|
|
166
|
+
background: rgba(99, 102, 241, 0.2);
|
|
167
|
+
color: #{config[:primary_color]};
|
|
168
|
+
font-weight: 500;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* Code blocks */
|
|
172
|
+
pre {
|
|
173
|
+
position: relative;
|
|
174
|
+
border-radius: 0.5rem;
|
|
175
|
+
overflow: hidden;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.copy-code-button {
|
|
179
|
+
position: absolute;
|
|
180
|
+
top: 0.5rem;
|
|
181
|
+
right: 0.5rem;
|
|
182
|
+
padding: 0.25rem 0.5rem;
|
|
183
|
+
font-size: 0.75rem;
|
|
184
|
+
border-radius: 0.25rem;
|
|
185
|
+
background: rgba(255, 255, 255, 0.9);
|
|
186
|
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
187
|
+
cursor: pointer;
|
|
188
|
+
opacity: 0;
|
|
189
|
+
transition: opacity 0.2s ease;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
pre:hover .copy-code-button {
|
|
193
|
+
opacity: 1;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.copy-code-button.copied {
|
|
197
|
+
background: rgba(34, 197, 94, 0.9);
|
|
198
|
+
color: white;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* Admonition styles */
|
|
202
|
+
.admonition {
|
|
203
|
+
border-radius: 0.5rem;
|
|
204
|
+
padding: 1rem;
|
|
205
|
+
margin: 1rem 0;
|
|
206
|
+
border-left: 4px solid;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.admonition-note {
|
|
210
|
+
background: rgba(59, 130, 246, 0.1);
|
|
211
|
+
border-color: rgb(59, 130, 246);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.admonition-tip {
|
|
215
|
+
background: rgba(34, 197, 94, 0.1);
|
|
216
|
+
border-color: rgb(34, 197, 94);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.admonition-warning {
|
|
220
|
+
background: rgba(251, 191, 36, 0.1);
|
|
221
|
+
border-color: rgb(251, 191, 36);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.admonition-caution {
|
|
225
|
+
background: rgba(239, 68, 68, 0.1);
|
|
226
|
+
border-color: rgb(239, 68, 68);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.admonition-important {
|
|
230
|
+
background: rgba(139, 92, 246, 0.1);
|
|
231
|
+
border-color: rgb(139, 92, 246);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* Print styles */
|
|
235
|
+
@media print {
|
|
236
|
+
#reading-progress,
|
|
237
|
+
#back-to-top,
|
|
238
|
+
#theme-toggle,
|
|
239
|
+
.toc-sidebar {
|
|
240
|
+
display: none !important;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.content-wrapper {
|
|
244
|
+
max-width: 100% !important;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#{config[:enable_animations] ? animation_css : ''}
|
|
249
|
+
CSS
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
private
|
|
253
|
+
|
|
254
|
+
# Animation CSS
|
|
255
|
+
#
|
|
256
|
+
# @return [String] Animation CSS
|
|
257
|
+
def animation_css
|
|
258
|
+
<<~CSS
|
|
259
|
+
/* Animations */
|
|
260
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
261
|
+
.animate-fade-in {
|
|
262
|
+
animation: fadeIn 0.3s ease-out;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.animate-slide-up {
|
|
266
|
+
animation: slideUp 0.3s ease-out;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.animate-scale-in {
|
|
270
|
+
animation: scaleIn 0.3s ease-out;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
@keyframes fadeIn {
|
|
275
|
+
from {
|
|
276
|
+
opacity: 0;
|
|
277
|
+
}
|
|
278
|
+
to {
|
|
279
|
+
opacity: 1;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
@keyframes slideUp {
|
|
284
|
+
from {
|
|
285
|
+
opacity: 0;
|
|
286
|
+
transform: translateY(10px);
|
|
287
|
+
}
|
|
288
|
+
to {
|
|
289
|
+
opacity: 1;
|
|
290
|
+
transform: translateY(0);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
@keyframes scaleIn {
|
|
295
|
+
from {
|
|
296
|
+
opacity: 0;
|
|
297
|
+
transform: scale(0.95);
|
|
298
|
+
}
|
|
299
|
+
to {
|
|
300
|
+
opacity: 1;
|
|
301
|
+
transform: scale(1);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
CSS
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
end
|