scriptorium 0.0.3 → 0.6.1

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 (292) hide show
  1. checksums.yaml +4 -4
  2. data/README.lt3 +324 -0
  3. data/README.md +3155 -1
  4. data/assets/.DS_Store +0 -0
  5. data/assets/README.md +44 -0
  6. data/assets/back-icon.png +0 -0
  7. data/assets/icons/facebook.svg +1 -0
  8. data/assets/icons/github.svg +1 -0
  9. data/assets/icons/instagram.svg +1 -0
  10. data/assets/icons/reddit.svg +1 -0
  11. data/assets/icons/ui/.DS_Store +0 -0
  12. data/assets/icons/ui/back.png +0 -0
  13. data/assets/icons/ui/copy.png +0 -0
  14. data/assets/icons/ui/down.png +0 -0
  15. data/assets/icons/ui/end.png +0 -0
  16. data/assets/icons/ui/exit.png +0 -0
  17. data/assets/icons/ui/foo +10 -0
  18. data/assets/icons/ui/home.png +0 -0
  19. data/assets/icons/ui/left.png +0 -0
  20. data/assets/icons/ui/next.png +0 -0
  21. data/assets/icons/ui/right.png +0 -0
  22. data/assets/icons/ui/start.png +0 -0
  23. data/assets/icons/ui/up.png +0 -0
  24. data/assets/icons/x.svg +1 -0
  25. data/assets/icons/youtube.svg +1 -0
  26. data/assets/samples/placeholder.svg +9 -0
  27. data/assets/themes/standard/favicon.svg +6 -0
  28. data/bin/scriptorium +1511 -0
  29. data/doc/README.txt +6 -0
  30. data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +95 -0
  31. data/doc/anti-amnesia/20250727-060000-api-design-tui-planning.md +34 -0
  32. data/doc/anti-amnesia/20250727-061000-runeblog-tui-analysis.md +50 -0
  33. data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +31 -0
  34. data/doc/anti-amnesia/20250727-154000-livetext-plugin-file-stats.md +73 -0
  35. data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +64 -0
  36. data/doc/anti-amnesia/20250727-172600-unified-minitest-framework.md +70 -0
  37. data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +40 -0
  38. data/doc/anti-amnesia/20250727-173000-widget-testing-achievement.md +110 -0
  39. data/doc/anti-amnesia/20250727-180000-post-id-num-refactoring.md +73 -0
  40. data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +46 -0
  41. data/doc/anti-amnesia/20250728-124421-conversation-summary-concise.md +124 -0
  42. data/doc/anti-amnesia/20250729-190000-scriptorium-tui-testing-complete.md +46 -0
  43. data/doc/anti-amnesia/20250729-200000-scriptorium-tui-testing-edit-file-workflow.md +97 -0
  44. data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +158 -0
  45. data/doc/anti-amnesia/20250729-211500-dependency-management-system.md +211 -0
  46. data/doc/anti-amnesia/20250729-213000-python-virtual-environment-setup.md +141 -0
  47. data/doc/anti-amnesia/20250729-214500-theme-management-commands.md +211 -0
  48. data/doc/anti-amnesia/20250729-215000-version-update-to-0.6.0.md +134 -0
  49. data/doc/anti-amnesia/20250729-220000-user-guide-complete.md +41 -0
  50. data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +45 -0
  51. data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +30 -0
  52. data/doc/anti-amnesia/20250804-213700-publishing-test-fix.md +49 -0
  53. data/doc/anti-amnesia/20250804-214400-additional-test-fixes.md +46 -0
  54. data/doc/anti-amnesia/20250804-220000-asset-function-logic-clarification.md +41 -0
  55. data/doc/anti-amnesia/20250806-202032-asset-function-logic-clarification.md +41 -0
  56. data/doc/anti-amnesia/20250807-213025.md +116 -0
  57. data/doc/anti-amnesia/20250813-082428-syntax-highlighting-and-navigation-improvements.md +256 -0
  58. data/doc/banner_svg_config.md +114 -0
  59. data/doc/contrib.lt3 +8 -0
  60. data/doc/dependencies.md +281 -0
  61. data/doc/hacker.lt3 +5 -0
  62. data/doc/reddit_credentials_template.json +8 -0
  63. data/doc/reddit_integration.md +207 -0
  64. data/doc/user.lt3 +38 -0
  65. data/doc/user_guide_section_1.md +137 -0
  66. data/doc/user_guide_section_10.md +515 -0
  67. data/doc/user_guide_section_11.md +708 -0
  68. data/doc/user_guide_section_2.md +233 -0
  69. data/doc/user_guide_section_3.md +5 -0
  70. data/doc/user_guide_section_4.md +221 -0
  71. data/doc/user_guide_section_5.md +243 -0
  72. data/doc/user_guide_section_6.md +147 -0
  73. data/doc/user_guide_section_7.md +311 -0
  74. data/doc/user_guide_section_8.md +224 -0
  75. data/doc/user_guide_section_9.md +375 -0
  76. data/doc/userdoc-toc.txt +88 -0
  77. data/lib/rouge/lexers/livetext.rb +74 -0
  78. data/lib/scriptorium/api.rb +640 -0
  79. data/lib/scriptorium/banner_svg.rb +742 -0
  80. data/lib/scriptorium/contract.rb +33 -0
  81. data/lib/scriptorium/exceptions.rb +170 -1
  82. data/lib/scriptorium/helpers.rb +475 -0
  83. data/lib/scriptorium/post.rb +195 -0
  84. data/lib/scriptorium/reddit.rb +83 -0
  85. data/lib/scriptorium/repo.rb +624 -0
  86. data/lib/scriptorium/standard_files.rb +515 -0
  87. data/lib/scriptorium/syntax_highlighter.rb +234 -0
  88. data/lib/scriptorium/theme.rb +179 -0
  89. data/lib/scriptorium/version.rb +2 -2
  90. data/lib/scriptorium/view.rb +976 -0
  91. data/lib/scriptorium/widgets/featured_posts.rb +149 -0
  92. data/lib/scriptorium/widgets/links.rb +112 -0
  93. data/lib/scriptorium/widgets/pages.rb +133 -0
  94. data/lib/scriptorium/widgets/widget.rb +133 -0
  95. data/lib/scriptorium.rb +21 -40
  96. data/lib/skeleton.rb +8 -2
  97. data/scriptorium.gemspec +15 -4
  98. data/test/README.md +69 -0
  99. data/test/all +43 -0
  100. data/test/api_demo.rb +99 -0
  101. data/test/assets/imagenotfound.jpg +0 -0
  102. data/test/assets/images/.DS_Store +0 -0
  103. data/test/assets/images/README.md +27 -0
  104. data/test/assets/images/odd_aspect.png +0 -0
  105. data/test/assets/images/perfect.png +0 -0
  106. data/test/assets/images/small.png +0 -0
  107. data/test/assets/images/tall.png +0 -0
  108. data/test/assets/images/very_tall.png +0 -0
  109. data/test/assets/images/very_wide.png +0 -0
  110. data/test/assets/images/wide.png +0 -0
  111. data/test/assets/testbanner.jpg +0 -0
  112. data/test/banner_svg/simple_helpers.rb +13 -0
  113. data/test/banner_svg/unit.rb +768 -0
  114. data/test/ed_test.rb +204 -0
  115. data/test/integration/cursor_banner_combinations.rb +193 -0
  116. data/test/integration/cursor_banner_features.rb +374 -0
  117. data/test/integration/integration_test.rb +326 -0
  118. data/test/livetext_plugin_test.rb +229 -0
  119. data/test/manual/asset_mgmt.rb +67 -0
  120. data/test/manual/banner-tests/config.txt +3 -0
  121. data/test/manual/banner-tests/index.html +45 -0
  122. data/test/manual/banner-tests/test01.html +58 -0
  123. data/test/manual/banner-tests/test02.html +58 -0
  124. data/test/manual/banner-tests/test03.html +58 -0
  125. data/test/manual/banner-tests/test04.html +65 -0
  126. data/test/manual/banner-tests/test05.html +65 -0
  127. data/test/manual/banner-tests/test06.html +65 -0
  128. data/test/manual/banner-tests/test07.html +65 -0
  129. data/test/manual/banner-tests/test08.html +59 -0
  130. data/test/manual/banner-tests/test09.html +59 -0
  131. data/test/manual/banner-tests/test10.html +59 -0
  132. data/test/manual/banner-tests/test11.html +59 -0
  133. data/test/manual/banner-tests/test12.html +59 -0
  134. data/test/manual/banner-tests/test13.html +59 -0
  135. data/test/manual/banner-tests/test14.html +59 -0
  136. data/test/manual/banner-tests/test15.html +58 -0
  137. data/test/manual/banner-tests/test16.html +58 -0
  138. data/test/manual/banner-tests/test17.html +58 -0
  139. data/test/manual/banner-tests/test18.html +68 -0
  140. data/test/manual/banner-tests/test19.html +68 -0
  141. data/test/manual/banner-tests/test20.html +68 -0
  142. data/test/manual/banner-tests/test21.html +68 -0
  143. data/test/manual/banner-tests/test22.html +68 -0
  144. data/test/manual/banner-tests/test23.html +68 -0
  145. data/test/manual/banner-tests/test24.html +68 -0
  146. data/test/manual/banner-tests/test25.html +67 -0
  147. data/test/manual/banner_environment.rb +192 -0
  148. data/test/manual/deploy_symlink_demo.rb +142 -0
  149. data/test/manual/environment.rb +67 -0
  150. data/test/manual/make_banner.rb +153 -0
  151. data/test/manual/sample_banner_config.txt +12 -0
  152. data/test/manual/symlink_demo.rb +117 -0
  153. data/test/manual/test1.rb +47 -0
  154. data/test/manual/test2.rb +12 -0
  155. data/test/manual/test3.rb +38 -0
  156. data/test/manual/test4.rb +40 -0
  157. data/test/manual/test5.rb +24 -0
  158. data/test/manual/test6.rb +73 -0
  159. data/test/manual/test_banner_combinations.rb +120 -0
  160. data/test/manual/test_banner_features.rb +306 -0
  161. data/test/manual/test_banner_from_file.rb +150 -0
  162. data/test/manual/test_banner_in_header.rb +35 -0
  163. data/test/manual/test_code_highlighting.rb +68 -0
  164. data/test/manual/test_complex_header.rb +74 -0
  165. data/test/manual/test_empty_header.rb +32 -0
  166. data/test/manual/test_radial_custom.rb +58 -0
  167. data/test/manual/test_radial_large_radius.rb +52 -0
  168. data/test/manual/test_svg_debug.rb +47 -0
  169. data/test/manual/test_syntax_highlighting.rb +147 -0
  170. data/test/pages-demo/config/currentview.txt +1 -0
  171. data/test/pages-demo/views/demo/config/bootstrap_css.txt +5 -0
  172. data/test/pages-demo/views/demo/config/bootstrap_js.txt +4 -0
  173. data/test/pages-demo/views/demo/config/common.js +57 -0
  174. data/test/pages-demo/views/demo/config/footer.txt +1 -0
  175. data/test/pages-demo/views/demo/config/global-head.txt +8 -0
  176. data/test/pages-demo/views/demo/config/header.txt +1 -0
  177. data/test/pages-demo/views/demo/config/layout.txt +1 -0
  178. data/test/pages-demo/views/demo/config/left.txt +1 -0
  179. data/test/pages-demo/views/demo/config/main.txt +1 -0
  180. data/test/pages-demo/views/demo/config/right.txt +1 -0
  181. data/test/pages-demo/views/demo/config.txt +3 -0
  182. data/test/pages-demo/views/demo/output/panes/footer.html +1 -0
  183. data/test/pages-demo/views/demo/output/panes/header.html +1 -0
  184. data/test/pages-demo/views/demo/output/panes/left.html +1 -0
  185. data/test/pages-demo/views/demo/output/panes/main.html +1 -0
  186. data/test/pages-demo/views/demo/output/panes/right.html +1 -0
  187. data/test/rubytext/rubytext_comprehensive_test.rb +307 -0
  188. data/test/rubytext/rubytext_demo_test.rb +42 -0
  189. data/test/rubytext/rubytext_testing_guide.md +277 -0
  190. data/test/run_automated_tests.rb +45 -0
  191. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_css.txt +5 -0
  192. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_js.txt +4 -0
  193. data/test/scriptorium-TEST-1754622690-146/config/common.js +57 -0
  194. data/test/scriptorium-TEST-1754622690-146/config/currentview.txt +1 -0
  195. data/test/scriptorium-TEST-1754622690-146/config/global-head.txt +9 -0
  196. data/test/scriptorium-TEST-1754622690-146/config/last_post_num.txt +1 -0
  197. data/test/scriptorium-TEST-1754622690-146/config/os_helpers.rb +4 -0
  198. data/test/scriptorium-TEST-1754622690-146/config/widgets.txt +3 -0
  199. data/test/scriptorium-TEST-1754622690-146/posts/0001/meta.txt +8 -0
  200. data/test/scriptorium-TEST-1754622690-146/posts/0001/source.lt3 +6 -0
  201. data/test/scriptorium-TEST-1754622690-146/themes/standard/README.txt +1 -0
  202. data/test/scriptorium-TEST-1754622690-146/themes/standard/config.txt +1 -0
  203. data/test/scriptorium-TEST-1754622690-146/themes/standard/initial/post.lt3 +12 -0
  204. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/footer.txt +2 -0
  205. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/header.txt +4 -0
  206. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/left.txt +3 -0
  207. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/main.txt +5 -0
  208. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/right.txt +3 -0
  209. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/gen/text.css +1 -0
  210. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/layout.txt +5 -0
  211. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index.lt3 +1 -0
  212. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index_entry.lt3 +14 -0
  213. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/post.lt3 +13 -0
  214. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/widget.lt3 +1 -0
  215. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_css.txt +5 -0
  216. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_js.txt +4 -0
  217. data/test/scriptorium-TEST-1754622690-146/views/sample/config/common.js +57 -0
  218. data/test/scriptorium-TEST-1754622690-146/views/sample/config/deploy.txt +5 -0
  219. data/test/scriptorium-TEST-1754622690-146/views/sample/config/footer.txt +2 -0
  220. data/test/scriptorium-TEST-1754622690-146/views/sample/config/global-head.txt +9 -0
  221. data/test/scriptorium-TEST-1754622690-146/views/sample/config/header.txt +4 -0
  222. data/test/scriptorium-TEST-1754622690-146/views/sample/config/layout.txt +5 -0
  223. data/test/scriptorium-TEST-1754622690-146/views/sample/config/left.txt +3 -0
  224. data/test/scriptorium-TEST-1754622690-146/views/sample/config/main.txt +5 -0
  225. data/test/scriptorium-TEST-1754622690-146/views/sample/config/reddit.txt +10 -0
  226. data/test/scriptorium-TEST-1754622690-146/views/sample/config/right.txt +3 -0
  227. data/test/scriptorium-TEST-1754622690-146/views/sample/config/social.txt +7 -0
  228. data/test/scriptorium-TEST-1754622690-146/views/sample/config/status.txt +7 -0
  229. data/test/scriptorium-TEST-1754622690-146/views/sample/config.txt +3 -0
  230. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/footer.html +3 -0
  231. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/header.html +3 -0
  232. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/left.html +3 -0
  233. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/main.html +3 -0
  234. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/right.html +3 -0
  235. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/footer.html +1 -0
  236. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/header.html +1 -0
  237. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/left.html +1 -0
  238. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/main.html +1 -0
  239. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/right.html +1 -0
  240. data/test/staging/.DS_Store +0 -0
  241. data/test/syntax_highlighting_test.lt3 +124 -0
  242. data/test/test_helpers.rb +230 -0
  243. data/test/tui_editor_integration_test.rb +296 -0
  244. data/test/tui_integration_test.rb +637 -0
  245. data/test/unit/api.rb +1056 -0
  246. data/test/unit/asset_management.rb +245 -0
  247. data/test/unit/clipboard_test.rb +60 -0
  248. data/test/unit/contract_test.rb +91 -0
  249. data/test/unit/core.rb +857 -0
  250. data/test/unit/deploy_test.rb +187 -0
  251. data/test/unit/gem_asset_management.rb +189 -0
  252. data/test/unit/livetext_basic.rb +69 -0
  253. data/test/unit/livetext_compatibility.rb +89 -0
  254. data/test/unit/post.rb +244 -0
  255. data/test/unit/read_commented_file_test.rb +276 -0
  256. data/test/unit/reddit_test.rb +235 -0
  257. data/test/unit/repo.rb +548 -0
  258. data/test/unit/social_test.rb +369 -0
  259. data/test/unit/symlink_test.rb +213 -0
  260. data/test/unit/view.rb +431 -0
  261. data/test/unit/widgets.rb +669 -0
  262. data/test/wizard_test.rb +123 -0
  263. data/ui/README.md +67 -0
  264. data/ui/common/lib/ui_common.rb +8 -0
  265. data/ui/rubytext/README.md +191 -0
  266. data/ui/rubytext/bin/scriptorium-rubytext +402 -0
  267. data/ui/rubytext/lib/rubytext_ui.rb +300 -0
  268. data/ui/tui/bin/scriptorium +1420 -0
  269. data/ui/tui/test/tui_test.rb +23 -0
  270. data/ui/web/app/app.rb +1378 -0
  271. data/ui/web/app/error_helpers.rb +150 -0
  272. data/ui/web/app/views/advanced_config.erb +190 -0
  273. data/ui/web/app/views/asset_management.erb +589 -0
  274. data/ui/web/app/views/banner_config.erb +200 -0
  275. data/ui/web/app/views/configure_view.erb +401 -0
  276. data/ui/web/app/views/dashboard.erb +162 -0
  277. data/ui/web/app/views/deploy_config.erb +146 -0
  278. data/ui/web/app/views/edit_pages.erb +195 -0
  279. data/ui/web/app/views/edit_post.erb +54 -0
  280. data/ui/web/app/views/error_page.erb +29 -0
  281. data/ui/web/app/views/header_config.erb +155 -0
  282. data/ui/web/app/views/layout_config.erb +147 -0
  283. data/ui/web/app/views/navbar_config.erb +411 -0
  284. data/ui/web/app/views/view_dashboard.erb +138 -0
  285. data/ui/web/bin/scriptorium-web +153 -0
  286. data/ui/web/test/web_basic_test.rb +38 -0
  287. data/ui/web/test_navbar.txt +7 -0
  288. data/ui/web/tmp/web_server.log +5 -0
  289. data/ui/web/tmp/web_server.pid +1 -0
  290. metadata +359 -7
  291. data/lib/scriptorium/engine.rb +0 -22
  292. data/test/engine/unit.rb +0 -44
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../../lib/scriptorium'
4
+
5
+ include Scriptorium::Helpers
6
+
7
+ # Simple banner test from configuration file
8
+ def test_banner_from_file(config_file, output_file = nil)
9
+ # Default output file if not specified
10
+ output_file ||= "banner_output.html"
11
+
12
+ # Read the configuration file
13
+ unless File.exist?(config_file)
14
+ puts "Error: Configuration file '#{config_file}' not found"
15
+ exit 1
16
+ end
17
+
18
+ # Use the read_commented_file helper to read the config
19
+ config_lines = read_commented_file(config_file)
20
+ config_content = File.read(config_file) # Keep original for display
21
+
22
+ puts "Read configuration from: #{config_file}"
23
+ puts "Found #{config_lines.length} configuration lines (comments removed)"
24
+
25
+ # Create banner with default title/subtitle
26
+ banner = Scriptorium::BannerSVG.new("Test Banner", "Generated from config file")
27
+
28
+ # Write config to temporary file for banner to read
29
+ temp_config = "temp_banner_config.txt"
30
+ File.write(temp_config, config_content)
31
+
32
+ # Parse and generate the banner
33
+ banner.parse_header_svg
34
+ svg_output = banner.generate_svg
35
+
36
+ # Clean up temp config file
37
+ File.delete(temp_config) if File.exist?(temp_config)
38
+
39
+ # Create HTML output
40
+ html_content = <<~HTML
41
+ <!DOCTYPE html>
42
+ <html>
43
+ <head>
44
+ <title>Banner Test - #{File.basename(config_file)}</title>
45
+ <style>
46
+ body {
47
+ font-family: Arial, sans-serif;
48
+ margin: 0;
49
+ padding: 20px;
50
+ background: #f5f5f5;
51
+ }
52
+ .banner {
53
+ width: 100%;
54
+ max-width: 800px;
55
+ margin: 0 auto 20px auto;
56
+ border: 2px solid #007cba;
57
+ border-radius: 8px;
58
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
59
+ }
60
+ .config {
61
+ background: white;
62
+ padding: 20px;
63
+ margin: 20px auto;
64
+ max-width: 800px;
65
+ border-radius: 8px;
66
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
67
+ }
68
+ .config h3 {
69
+ margin-top: 0;
70
+ color: #333;
71
+ }
72
+ .config pre {
73
+ background: #f8f9fa;
74
+ padding: 15px;
75
+ border-radius: 4px;
76
+ overflow-x: auto;
77
+ font-family: monospace;
78
+ font-size: 12px;
79
+ }
80
+ .info {
81
+ background: white;
82
+ padding: 20px;
83
+ margin: 20px auto;
84
+ max-width: 800px;
85
+ border-radius: 8px;
86
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
87
+ }
88
+ .processed-config {
89
+ background: #e8f4fd;
90
+ padding: 15px;
91
+ margin: 10px 0;
92
+ border-radius: 4px;
93
+ font-family: monospace;
94
+ font-size: 12px;
95
+ }
96
+ </style>
97
+ </head>
98
+ <body>
99
+ <div class="banner">
100
+ #{svg_output}
101
+ </div>
102
+
103
+ <div class="info">
104
+ <h3>Banner Information</h3>
105
+ <p><strong>Configuration file:</strong> #{config_file}</p>
106
+ <p><strong>Output file:</strong> #{output_file}</p>
107
+ <p><strong>Generated:</strong> #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}</p>
108
+ <p><strong>Configuration lines processed:</strong> #{config_lines.length}</p>
109
+ </div>
110
+
111
+ <div class="config">
112
+ <h3>Configuration Used (with comments)</h3>
113
+ <pre>#{config_content}</pre>
114
+
115
+ <h3>Processed Configuration (comments removed)</h3>
116
+ <div class="processed-config">
117
+ #{config_lines.map { |line| line.empty? ? "# (empty line)" : line }.join("\n")}
118
+ </div>
119
+ </div>
120
+ </body>
121
+ </html>
122
+ HTML
123
+
124
+ # Write the HTML file
125
+ File.write(output_file, html_content)
126
+ puts "Generated banner HTML: #{output_file}"
127
+
128
+ # Open in browser if on macOS
129
+ if RUBY_PLATFORM.include?('darwin')
130
+ puts "Opening in browser..."
131
+ system("open #{output_file}")
132
+ else
133
+ puts "Open #{output_file} in your browser to view the banner"
134
+ end
135
+ end
136
+
137
+ # Main execution
138
+ if ARGV.empty?
139
+ puts "Usage: ruby test_banner_from_file.rb <config_file> [output_file]"
140
+ puts ""
141
+ puts "Example:"
142
+ puts " ruby test_banner_from_file.rb my_banner_config.txt"
143
+ puts " ruby test_banner_from_file.rb my_banner_config.txt custom_output.html"
144
+ exit 1
145
+ end
146
+
147
+ config_file = ARGV[0]
148
+ output_file = ARGV[1] # Optional
149
+
150
+ test_banner_from_file(config_file, output_file)
@@ -0,0 +1,35 @@
1
+ require_relative './environment'
2
+
3
+ manual_setup
4
+
5
+ # Create a simple view
6
+ view = @repo.create_view("banner-test", "My Banner Site", "A site with SVG banner in header")
7
+
8
+ # Set up layout with header
9
+ File.open(view.dir/:config/"layout.txt", "w") do |f|
10
+ f.puts "header"
11
+ f.puts "main"
12
+ end
13
+
14
+ # Generate the empty containers
15
+ view.generate_empty_containers
16
+
17
+ # Configure the header to include the SVG banner
18
+ File.open(view.dir/:config/"header.txt", "w") do |f|
19
+ f.puts "banner svg"
20
+ end
21
+
22
+ # Generate the front page
23
+ view.generate_front_page
24
+
25
+ instruct <<~EOS
26
+ This test shows how to insert an SVG banner into the header.
27
+
28
+ The header.txt contains:
29
+ - banner svg (inserts the SVG banner)
30
+
31
+ The SVG banner will appear at the top of the header.
32
+ The banner automatically uses the view's title and subtitle as its content.
33
+ EOS
34
+
35
+ examine view
@@ -0,0 +1,68 @@
1
+ require_relative "./environment"
2
+
3
+ manual_setup
4
+
5
+ @repo.create_view("testview", "Test View", "A test view for manual inspection")
6
+
7
+ # Post with code highlighting
8
+ draft_body = <<~BODY
9
+ .blurb Testing code highlighting with Prism.
10
+ This post tests the .code function and Prism syntax highlighting.
11
+
12
+ Here's some Ruby code:
13
+
14
+ .code ruby
15
+ def hello_world
16
+ puts "Hello, World!"
17
+ @greeting = "Welcome to Scriptorium"
18
+ return @greeting
19
+ end
20
+ .end
21
+
22
+ And some JavaScript:
23
+
24
+ .code javascript
25
+ function greet(name) {
26
+ console.log("Hello, " + name);
27
+ return "Greeting sent";
28
+ }
29
+ .end
30
+
31
+ And plain text:
32
+
33
+ .code text
34
+ This is just plain text
35
+ No syntax highlighting needed
36
+ But it should still be in a code block
37
+ .end
38
+
39
+ And some more Ruby:
40
+
41
+ .code ruby
42
+ class Example
43
+ def initialize
44
+ @data = []
45
+ end
46
+
47
+ def add_item(item)
48
+ @data << item
49
+ end
50
+ end
51
+ .end
52
+ BODY
53
+
54
+ name = @repo.create_draft(title: "Code Highlighting Test", views: ["testview"], body: draft_body)
55
+ num = @repo.finish_draft(name)
56
+ @repo.generate_post(num)
57
+
58
+ @repo.generate_front_page("testview")
59
+
60
+ instruct <<~EOS
61
+ Front page should have one post with code highlighting.
62
+ Ruby code should be highlighted with Ruby syntax.
63
+ JavaScript code should be highlighted with JS syntax.
64
+ Plain text should be in code blocks but not highlighted.
65
+ Check that Prism CSS and JS are included in the generated HTML.
66
+ EOS
67
+
68
+ examine("testview")
@@ -0,0 +1,74 @@
1
+ require_relative './environment'
2
+
3
+ manual_setup
4
+
5
+ # Create a view with a complex header
6
+ view = @repo.create_view("complex-header", "My Awesome Blog", "Exploring the Power of SVG Banners")
7
+
8
+ # Set up layout with header
9
+ File.open(view.dir/:config/"layout.txt", "w") do |f|
10
+ f.puts "header"
11
+ f.puts "main"
12
+ end
13
+
14
+ # Generate the empty containers
15
+ view.generate_empty_containers
16
+
17
+ # Create a complex SVG banner configuration
18
+ File.open(view.dir/:config/"header.txt", "w") do |f|
19
+ f.puts "banner_svg"
20
+ f.puts "title"
21
+ f.puts "subtitle"
22
+ end
23
+
24
+ # Create a complex SVG banner config file
25
+ File.open(view.dir/:config/"config.txt", "w") do |f|
26
+ f.puts "# Complex SVG Banner Configuration"
27
+ f.puts "# This exercises multiple features at once"
28
+ f.puts ""
29
+ f.puts "# Background: Radial gradient from purple to blue"
30
+ f.puts "back.radial #8B5CF6 #3B82F6"
31
+ f.puts ""
32
+ f.puts "# Custom aspect ratio (wider banner)"
33
+ f.puts "aspect 6.0"
34
+ f.puts ""
35
+ f.puts "# Custom font"
36
+ f.puts "text.font Georgia serif"
37
+ f.puts ""
38
+ f.puts "# Title styling: Bold, larger scale, custom color"
39
+ f.puts "title.scale 1.2"
40
+ f.puts "title.style bold"
41
+ f.puts "title.color #FFFFFF"
42
+ f.puts "title.align center"
43
+ f.puts ""
44
+ f.puts "# Subtitle styling: Italic, smaller scale, different color"
45
+ f.puts "subtitle.scale 0.6"
46
+ f.puts "subtitle.style italic"
47
+ f.puts "subtitle.color #E5E7EB"
48
+ f.puts "subtitle.align center"
49
+ f.puts ""
50
+ f.puts "# Custom positioning for both title and subtitle"
51
+ f.puts "title.xy 50% 45%"
52
+ f.puts "subtitle.xy 50% 75%"
53
+ end
54
+
55
+ # Generate the front page
56
+ view.generate_front_page
57
+
58
+ instruct <<~EOS
59
+ Complex Header Test - Multiple SVG Banner Features
60
+
61
+ This header demonstrates:
62
+ - Radial gradient background (purple to blue)
63
+ - Custom aspect ratio (6:1 - wider banner)
64
+ - Georgia serif font
65
+ - Title: Bold, larger scale (1.2x), white color, centered
66
+ - Subtitle: Italic, smaller scale (0.6x), light gray color, centered
67
+ - Custom positioning for both title and subtitle
68
+ - Responsive SVG that scales with window width
69
+
70
+ The banner should look sophisticated with the gradient background
71
+ and well-positioned, styled text elements.
72
+ EOS
73
+
74
+ examine view
@@ -0,0 +1,32 @@
1
+ require_relative './environment'
2
+
3
+ manual_setup
4
+
5
+ # Create a view with an empty header
6
+ view = @repo.create_view("empty-header-test", "Empty Header Test", "Testing placeholder text")
7
+
8
+ # Set up layout with header
9
+ File.open(view.dir/:config/"layout.txt", "w") do |f|
10
+ f.puts "header"
11
+ f.puts "main"
12
+ end
13
+
14
+ # Generate the empty containers
15
+ view.generate_empty_containers
16
+
17
+ # Leave header.txt empty (no content)
18
+ File.open(view.dir/:config/"header.txt", "w") do |f|
19
+ # Empty file - should trigger placeholder
20
+ end
21
+
22
+ # Generate the front page
23
+ view.generate_front_page
24
+
25
+ instruct <<~EOS
26
+ This test verifies that placeholder text appears when header has no content.
27
+
28
+ The header.txt is empty, so it should show "This is header..." as placeholder text.
29
+ This confirms that our fix only removes placeholders when there's real content.
30
+ EOS
31
+
32
+ examine view
@@ -0,0 +1,58 @@
1
+ require_relative './environment'
2
+
3
+ manual_setup
4
+
5
+ # Create a view with custom radial gradient
6
+ view = @repo.create_view("radial-custom", "Custom Radial Test", "Testing custom radial gradient parameters")
7
+
8
+ # Set up layout with header
9
+ File.open(view.dir/:config/"layout.txt", "w") do |f|
10
+ f.puts "header"
11
+ end
12
+
13
+ # Generate the empty containers
14
+ view.generate_empty_containers
15
+
16
+ # Configure the header to only have the SVG banner
17
+ File.open(view.dir/:config/"header.txt", "w") do |f|
18
+ f.puts "banner_svg"
19
+ end
20
+
21
+ # Create a custom radial gradient config
22
+ File.open(view.dir/:config/"config.txt", "w") do |f|
23
+ f.puts "# Custom Radial Gradient Test"
24
+ f.puts "# Default: circular vignette (ar omitted, will use 1/aspect)"
25
+ f.puts "aspect 5.0"
26
+ f.puts "back.radial #FF6B6B #4ECDC4 75% 25% 60%"
27
+ f.puts ""
28
+ f.puts "# Custom: elliptical vignette (ar = 0.5, i.e. squished horizontally)"
29
+ f.puts "# Uncomment to test:"
30
+ f.puts "# back.radial #FF6B6B #4ECDC4 75% 25% 60% 0.5"
31
+ f.puts ""
32
+ f.puts "# Title styling"
33
+ f.puts "title.color #FFFFFF"
34
+ f.puts "title.style bold"
35
+ f.puts "title.align center"
36
+ f.puts ""
37
+ f.puts "# Subtitle styling"
38
+ f.puts "subtitle.color #FFFFFF"
39
+ f.puts "subtitle.style italic"
40
+ f.puts "subtitle.align center"
41
+ end
42
+
43
+ # Generate the front page
44
+ view.generate_front_page
45
+
46
+ instruct <<~EOS
47
+ Custom Radial Gradient Test
48
+
49
+ This test demonstrates the new aspect-ratio compensation for radial gradients:
50
+ - aspect 5.0 (wide banner)
51
+ - back.radial #FF6B6B #4ECDC4 75% 25% 60% # default: circular vignette
52
+ - Uncomment the line with ar=0.5 for an elliptical vignette
53
+
54
+ By default, the vignette should be circular even in a wide banner.
55
+ If you set ar < 1/aspect, the vignette will be squished horizontally.
56
+ EOS
57
+
58
+ examine view
@@ -0,0 +1,52 @@
1
+ require_relative './environment'
2
+
3
+ manual_setup
4
+
5
+ # Create a view with a large-radius radial gradient
6
+ view = @repo.create_view("radial-large-radius", "Large Radius Radial Test", "Testing r > 100% for soft vignette")
7
+
8
+ # Set up layout with header
9
+ File.open(view.dir/:config/"layout.txt", "w") do |f|
10
+ f.puts "header"
11
+ end
12
+
13
+ # Generate the empty containers
14
+ view.generate_empty_containers
15
+
16
+ # Configure the header to only have the SVG banner
17
+ File.open(view.dir/:config/"header.txt", "w") do |f|
18
+ f.puts "banner_svg"
19
+ end
20
+
21
+ # Create a config with a large radius
22
+ File.open(view.dir/:config/"config.txt", "w") do |f|
23
+ f.puts "# Large Radius Radial Gradient Test"
24
+ f.puts "aspect 5.0"
25
+ f.puts "# r = 150% (soft vignette, gradient extends beyond banner)"
26
+ f.puts "back.radial #FF6B6B #4ECDC4 50% 50% 150%"
27
+ f.puts ""
28
+ f.puts "# Title styling"
29
+ f.puts "title.color #FFFFFF"
30
+ f.puts "title.style bold"
31
+ f.puts "title.align center"
32
+ f.puts ""
33
+ f.puts "# Subtitle styling"
34
+ f.puts "subtitle.color #FFFFFF"
35
+ f.puts "subtitle.style italic"
36
+ f.puts "subtitle.align center"
37
+ end
38
+
39
+ # Generate the front page
40
+ view.generate_front_page
41
+
42
+ instruct <<~EOS
43
+ Large Radius Radial Gradient Test
44
+
45
+ This test demonstrates a radial gradient with r > 100% (here, 150%).
46
+ - aspect 5.0 (wide banner)
47
+ - back.radial #FF6B6B #4ECDC4 50% 50% 150%
48
+
49
+ The gradient should be very soft, with the color fading in from outside the banner.
50
+ EOS
51
+
52
+ examine view
@@ -0,0 +1,47 @@
1
+ require_relative './environment'
2
+
3
+ manual_setup
4
+
5
+ # Create a simple view for debugging
6
+ view = @repo.create_view("svg-debug", "SVG Debug Test", "Testing SVG insertion")
7
+
8
+ # Set up layout with header only
9
+ File.open(view.dir/:config/"layout.txt", "w") do |f|
10
+ f.puts "header"
11
+ end
12
+
13
+ # Generate the empty containers
14
+ view.generate_empty_containers
15
+
16
+ # Configure the header to only have the SVG banner
17
+ File.open(view.dir/:config/"header.txt", "w") do |f|
18
+ f.puts "banner_svg"
19
+ end
20
+
21
+ # Create a simple SVG config
22
+ File.open(view.dir/:config/"config.txt", "w") do |f|
23
+ f.puts "# Simple debug config"
24
+ f.puts "back.radial #FF0000 #0000FF"
25
+ f.puts "title.color #FFFFFF"
26
+ f.puts "subtitle.color #FFFF00"
27
+ f.puts "title.style bold"
28
+ f.puts "subtitle.style italic"
29
+ end
30
+
31
+ # Generate the front page
32
+ view.generate_front_page
33
+
34
+ instruct <<~EOS
35
+ SVG Debug Test
36
+
37
+ This test has:
38
+ - Only the SVG banner (no title/subtitle HTML elements)
39
+ - Red to blue radial gradient
40
+ - White bold title
41
+ - Yellow italic subtitle
42
+ - No header background color
43
+
44
+ Check if the SVG displays correctly now.
45
+ EOS
46
+
47
+ examine view
@@ -0,0 +1,147 @@
1
+ require_relative "./environment"
2
+
3
+ manual_setup
4
+
5
+ @repo.create_view("testview", "Test View", "A test view for manual inspection")
6
+
7
+ # Enable syntax highlighting for this test by adding it to global-head.txt
8
+ global_head_file = "test/scriptorium-TEST/views/testview/config/global-head.txt"
9
+ File.open(global_head_file, "a") { |f| f.puts "syntax # Enable Rouge syntax highlighting" }
10
+
11
+ # Post with Rouge syntax highlighting for multiple languages
12
+ draft_body = <<~'BODY'
13
+ .blurb Testing Rouge syntax highlighting for Ruby, Elixir, and JavaScript.
14
+ This post tests the integrated Rouge syntax highlighter with three different programming languages.
15
+
16
+ ## Ruby Code Example
17
+
18
+ .code ruby
19
+ class User
20
+ attr_accessor :name, :email
21
+
22
+ def initialize(name, email)
23
+ @name = name
24
+ @email = email
25
+ end
26
+
27
+ def greet
28
+ puts "Hello, #{@name}!"
29
+ end
30
+
31
+ def valid_email?
32
+ email.match?(/\\A[\\w+\\-.]+@[a-z\\d\\-]+(\\.[a-z\\d\\-]+)*\\.[a-z]+\\z/i)
33
+ end
34
+ end
35
+
36
+ user = User.new("Alice", "alice@example.com")
37
+ user.greet
38
+ .end
39
+
40
+ ## Elixir Code Example
41
+
42
+ .code elixir
43
+ defmodule Calculator do
44
+ def add(a, b), do: a + b
45
+ def subtract(a, b), do: a - b
46
+ def multiply(a, b), do: a * b
47
+ def divide(a, b) when b != 0, do: a / b
48
+ def divide(_, 0), do: {:error, "Division by zero"}
49
+
50
+ def calculate(operation, a, b) do
51
+ case operation do
52
+ :add -> add(a, b)
53
+ :subtract -> subtract(a, b)
54
+ :multiply -> multiply(a, b)
55
+ :divide -> divide(a, b)
56
+ _ -> {:error, "Unknown operation"}
57
+ end
58
+ end
59
+ end
60
+
61
+ # Test the calculator
62
+ IO.puts("5 + 3 = 8")
63
+ .end
64
+
65
+ ## JavaScript Code Example
66
+
67
+ .code javascript
68
+ class TodoList {
69
+ constructor() {
70
+ this.todos = [];
71
+ this.nextId = 1;
72
+ }
73
+
74
+ addTodo(text, completed = false) {
75
+ const todo = {
76
+ id: this.nextId++,
77
+ text: text,
78
+ completed: completed,
79
+ createdAt: new Date()
80
+ };
81
+
82
+ this.todos.push(todo);
83
+ return todo;
84
+ }
85
+
86
+ toggleTodo(id) {
87
+ const todo = this.todos.find(t => t.id === id);
88
+ if (todo) {
89
+ todo.completed = !todo.completed;
90
+ }
91
+ return todo;
92
+ }
93
+
94
+ removeTodo(id) {
95
+ const index = this.todos.findIndex(t => t.id === id);
96
+ if (index > -1) {
97
+ return this.todos.splice(index, 1)[0];
98
+ }
99
+ return null;
100
+ }
101
+
102
+ getCompletedTodos() {
103
+ return this.todos.filter(t => t.completed);
104
+ }
105
+
106
+ getPendingTodos() {
107
+ return this.todos.filter(t => !t.completed);
108
+ }
109
+ }
110
+
111
+ // Usage example
112
+ const todoList = new TodoList();
113
+ todoList.addTodo("Learn Rouge syntax highlighting");
114
+ todoList.addTodo("Test multiple languages");
115
+ todoList.addTodo("Write documentation", true);
116
+
117
+ console.log("Pending todos:", todoList.getPendingTodos().length);
118
+ console.log("Completed todos:", todoList.getCompletedTodos().length);
119
+ .end
120
+
121
+ ## Test Results
122
+
123
+ Each code block above should display with proper syntax highlighting:
124
+
125
+ - **Ruby**: Keywords in red, strings in blue, variables in orange
126
+ - **Elixir**: Functions in purple, atoms in green, strings in blue
127
+ - **JavaScript**: Keywords in red, functions in purple, strings in blue
128
+
129
+ The highlighting should work automatically thanks to our Rouge integration!
130
+ BODY
131
+
132
+ name = @repo.create_draft(title: "Rouge Syntax Highlighting Test", views: ["testview"], body: draft_body)
133
+ num = @repo.finish_draft(name)
134
+ @repo.generate_post(num)
135
+
136
+ @repo.generate_front_page("testview")
137
+
138
+ instruct <<~EOS
139
+ Front page should have one post with Rouge syntax highlighting.
140
+ Ruby code should be highlighted with Ruby syntax (keywords red, strings blue, variables orange).
141
+ Elixir code should be highlighted with Elixir syntax (functions purple, atoms green, strings blue).
142
+ JavaScript code should be highlighted with JS syntax (keywords red, functions purple, strings blue).
143
+ Check that Rouge CSS is included in the generated HTML.
144
+ All code blocks should have proper token classes and syntax highlighting.
145
+ EOS
146
+
147
+ examine("testview")
@@ -0,0 +1 @@
1
+ demo
@@ -0,0 +1,5 @@
1
+ href https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css
2
+ rel stylesheet
3
+ # integrity has a problem - compute instead?
4
+ # integrity sha384-KyZXEJ04F5o1v7V5b7ZMjGhGjxA8yQmBfvZwzI1r+0gEv+9KnQIMJxWwzD0u8nZ7
5
+ # crossorigin anonymous
@@ -0,0 +1,4 @@
1
+ src https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js
2
+ # integrity has a problem - compute instead?
3
+ # integrity sha384-pzjw8f+ua7Kw1TIq0+v5+GZkR6P/6v03cI0myXcJU22Hc5p5BY5/X93HmaJXjm4C
4
+ crossorigin anonymous