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.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/lib/coradoc/html/base.rb +157 -0
  4. data/lib/coradoc/html/config.rb +467 -0
  5. data/lib/coradoc/html/converter_base.rb +177 -0
  6. data/lib/coradoc/html/converters/admonition.rb +180 -0
  7. data/lib/coradoc/html/converters/attribute.rb +68 -0
  8. data/lib/coradoc/html/converters/attribute_reference.rb +60 -0
  9. data/lib/coradoc/html/converters/audio.rb +165 -0
  10. data/lib/coradoc/html/converters/base.rb +615 -0
  11. data/lib/coradoc/html/converters/bibliography.rb +82 -0
  12. data/lib/coradoc/html/converters/bibliography_entry.rb +108 -0
  13. data/lib/coradoc/html/converters/block_image.rb +72 -0
  14. data/lib/coradoc/html/converters/bold.rb +34 -0
  15. data/lib/coradoc/html/converters/break.rb +32 -0
  16. data/lib/coradoc/html/converters/comment_block.rb +42 -0
  17. data/lib/coradoc/html/converters/comment_line.rb +54 -0
  18. data/lib/coradoc/html/converters/cross_reference.rb +59 -0
  19. data/lib/coradoc/html/converters/document.rb +108 -0
  20. data/lib/coradoc/html/converters/example.rb +114 -0
  21. data/lib/coradoc/html/converters/highlight.rb +34 -0
  22. data/lib/coradoc/html/converters/include.rb +68 -0
  23. data/lib/coradoc/html/converters/inline_image.rb +41 -0
  24. data/lib/coradoc/html/converters/italic.rb +34 -0
  25. data/lib/coradoc/html/converters/line_break.rb +31 -0
  26. data/lib/coradoc/html/converters/link.rb +46 -0
  27. data/lib/coradoc/html/converters/list_item.rb +75 -0
  28. data/lib/coradoc/html/converters/listing.rb +99 -0
  29. data/lib/coradoc/html/converters/literal.rb +102 -0
  30. data/lib/coradoc/html/converters/monospace.rb +34 -0
  31. data/lib/coradoc/html/converters/open.rb +78 -0
  32. data/lib/coradoc/html/converters/ordered.rb +53 -0
  33. data/lib/coradoc/html/converters/paragraph.rb +46 -0
  34. data/lib/coradoc/html/converters/quote.rb +113 -0
  35. data/lib/coradoc/html/converters/reviewer_comment.rb +74 -0
  36. data/lib/coradoc/html/converters/reviewer_note.rb +134 -0
  37. data/lib/coradoc/html/converters/section.rb +90 -0
  38. data/lib/coradoc/html/converters/sidebar.rb +113 -0
  39. data/lib/coradoc/html/converters/source.rb +137 -0
  40. data/lib/coradoc/html/converters/source_code.rb +16 -0
  41. data/lib/coradoc/html/converters/span.rb +61 -0
  42. data/lib/coradoc/html/converters/strikethrough.rb +34 -0
  43. data/lib/coradoc/html/converters/subscript.rb +34 -0
  44. data/lib/coradoc/html/converters/superscript.rb +34 -0
  45. data/lib/coradoc/html/converters/table.rb +85 -0
  46. data/lib/coradoc/html/converters/table_cell.rb +203 -0
  47. data/lib/coradoc/html/converters/table_row.rb +45 -0
  48. data/lib/coradoc/html/converters/template_html_converter.rb +105 -0
  49. data/lib/coradoc/html/converters/term.rb +58 -0
  50. data/lib/coradoc/html/converters/text_element.rb +44 -0
  51. data/lib/coradoc/html/converters/underline.rb +34 -0
  52. data/lib/coradoc/html/converters/unordered.rb +47 -0
  53. data/lib/coradoc/html/converters/verse.rb +105 -0
  54. data/lib/coradoc/html/converters/video.rb +179 -0
  55. data/lib/coradoc/html/element_mapping.rb +210 -0
  56. data/lib/coradoc/html/entity.rb +137 -0
  57. data/lib/coradoc/html/input/cleaner.rb +163 -0
  58. data/lib/coradoc/html/input/config.rb +79 -0
  59. data/lib/coradoc/html/input/converters/a.rb +90 -0
  60. data/lib/coradoc/html/input/converters/aside.rb +23 -0
  61. data/lib/coradoc/html/input/converters/audio.rb +50 -0
  62. data/lib/coradoc/html/input/converters/base.rb +116 -0
  63. data/lib/coradoc/html/input/converters/blockquote.rb +25 -0
  64. data/lib/coradoc/html/input/converters/br.rb +19 -0
  65. data/lib/coradoc/html/input/converters/bypass.rb +83 -0
  66. data/lib/coradoc/html/input/converters/code.rb +25 -0
  67. data/lib/coradoc/html/input/converters/div.rb +25 -0
  68. data/lib/coradoc/html/input/converters/dl.rb +106 -0
  69. data/lib/coradoc/html/input/converters/drop.rb +28 -0
  70. data/lib/coradoc/html/input/converters/em.rb +23 -0
  71. data/lib/coradoc/html/input/converters/figure.rb +58 -0
  72. data/lib/coradoc/html/input/converters/h.rb +76 -0
  73. data/lib/coradoc/html/input/converters/head.rb +30 -0
  74. data/lib/coradoc/html/input/converters/hr.rb +20 -0
  75. data/lib/coradoc/html/input/converters/ignore.rb +22 -0
  76. data/lib/coradoc/html/input/converters/img.rb +110 -0
  77. data/lib/coradoc/html/input/converters/li.rb +35 -0
  78. data/lib/coradoc/html/input/converters/mark.rb +21 -0
  79. data/lib/coradoc/html/input/converters/markup.rb +107 -0
  80. data/lib/coradoc/html/input/converters/math.rb +46 -0
  81. data/lib/coradoc/html/input/converters/ol.rb +46 -0
  82. data/lib/coradoc/html/input/converters/p.rb +81 -0
  83. data/lib/coradoc/html/input/converters/pass_through.rb +19 -0
  84. data/lib/coradoc/html/input/converters/pre.rb +59 -0
  85. data/lib/coradoc/html/input/converters/q.rb +24 -0
  86. data/lib/coradoc/html/input/converters/strong.rb +22 -0
  87. data/lib/coradoc/html/input/converters/sub.rb +40 -0
  88. data/lib/coradoc/html/input/converters/sup.rb +40 -0
  89. data/lib/coradoc/html/input/converters/table.rb +64 -0
  90. data/lib/coradoc/html/input/converters/td.rb +70 -0
  91. data/lib/coradoc/html/input/converters/text.rb +67 -0
  92. data/lib/coradoc/html/input/converters/th.rb +20 -0
  93. data/lib/coradoc/html/input/converters/tr.rb +28 -0
  94. data/lib/coradoc/html/input/converters/video.rb +53 -0
  95. data/lib/coradoc/html/input/converters.rb +122 -0
  96. data/lib/coradoc/html/input/errors.rb +22 -0
  97. data/lib/coradoc/html/input/html_converter.rb +170 -0
  98. data/lib/coradoc/html/input/plugin.rb +169 -0
  99. data/lib/coradoc/html/input/plugins/plateau.rb +229 -0
  100. data/lib/coradoc/html/input/postprocessor.rb +31 -0
  101. data/lib/coradoc/html/input.rb +68 -0
  102. data/lib/coradoc/html/output.rb +95 -0
  103. data/lib/coradoc/html/renderer.rb +409 -0
  104. data/lib/coradoc/html/spa.rb +309 -0
  105. data/lib/coradoc/html/static.rb +293 -0
  106. data/lib/coradoc/html/template_config.rb +151 -0
  107. data/lib/coradoc/html/template_helpers.rb +58 -0
  108. data/lib/coradoc/html/template_locator.rb +114 -0
  109. data/lib/coradoc/html/theme/base.rb +231 -0
  110. data/lib/coradoc/html/theme/classic_renderer.rb +390 -0
  111. data/lib/coradoc/html/theme/modern/components/ui_components.rb +344 -0
  112. data/lib/coradoc/html/theme/modern/css_generator.rb +311 -0
  113. data/lib/coradoc/html/theme/modern/javascript_generator.rb +314 -0
  114. data/lib/coradoc/html/theme/modern/serializers/document_serializer.rb +382 -0
  115. data/lib/coradoc/html/theme/modern/tailwind_config_builder.rb +164 -0
  116. data/lib/coradoc/html/theme/modern/vue_template_generator.rb +374 -0
  117. data/lib/coradoc/html/theme/modern_renderer.rb +250 -0
  118. data/lib/coradoc/html/theme/registry.rb +153 -0
  119. data/lib/coradoc/html/theme.rb +13 -0
  120. data/lib/coradoc/html/transform/from_core_model.rb +32 -0
  121. data/lib/coradoc/html/transform/to_core_model.rb +39 -0
  122. data/lib/coradoc/html/version.rb +7 -0
  123. data/lib/coradoc/html.rb +255 -0
  124. 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