scriptorium 0.0.2 → 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 (290) 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 +174 -0
  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 +22 -9
  96. data/lib/skeleton.rb +11 -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 +360 -5
@@ -0,0 +1,47 @@
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 1
8
+ draft_1_body = <<~BODY
9
+ .blurb It's sort of the William Riker of blog posts.
10
+ This is the first post.
11
+
12
+ It contains multiple paragraphs:
13
+ - Introduction to the topic.<br>
14
+ - A deep dive into the details.<br>
15
+ - Conclusion with key takeaways.<br>
16
+
17
+ This should span multiple lines in the draft.
18
+ BODY
19
+
20
+ name1 = @repo.create_draft(title: "Post number one", views: ["testview"], body: draft_1_body)
21
+ num = @repo.finish_draft(name1)
22
+ @repo.generate_post(num)
23
+
24
+ # Post 2
25
+ draft_2_body = <<~BODY
26
+ .blurb In Roman numerals, this is post II.
27
+ This is the second post.
28
+
29
+ - Discussing the second topic.<br>
30
+ - Elaborating on several points.<br>
31
+ - Wrapping up with some additional comments.<br>
32
+
33
+ It also spans multiple lines in the draft.
34
+ BODY
35
+
36
+ name2 = @repo.create_draft(title: "Post number two", views: ["testview"], body: draft_2_body)
37
+ num = @repo.finish_draft(name2)
38
+ @repo.generate_post(num)
39
+
40
+ @repo.generate_front_page("testview") # Generate the front page
41
+
42
+ instruct <<~EOS
43
+ Front page should have two posts.
44
+ Each should have a blurb.
45
+ Links should work (and back button to return).
46
+ EOS
47
+ examine("testview")
@@ -0,0 +1,12 @@
1
+ require_relative "./environment"
2
+
3
+ manual_setup
4
+
5
+ create_3_views
6
+ @repo.generate_front_page("blog1")
7
+
8
+ instruct <<~EOS
9
+ Do we still need this test??
10
+ EOS
11
+
12
+ examine("blog1")
@@ -0,0 +1,38 @@
1
+ require_relative './environment'
2
+
3
+ # Handle --automated flag at the end
4
+ automated_mode = ARGV.last == '--automated'
5
+ if automated_mode
6
+ ARGV.pop # Remove --automated from ARGV
7
+ end
8
+
9
+ abort "Need a view name (blog1 blog2 blog3)" unless ARGV.size == 1
10
+
11
+ view = ARGV.first
12
+
13
+ # Restore --automated flag for the examine function
14
+ ARGV << '--automated' if automated_mode
15
+
16
+ manual_setup
17
+
18
+ srand(42) # for random posts
19
+
20
+ create_3_views
21
+ create_13_posts_manual
22
+ alter_pubdates
23
+
24
+ view = @repo.lookup_view(view)
25
+
26
+ instruct <<~EOS
27
+ Three blogs created: blog1 blog2 blog3
28
+ Browser goes to whichever you put on command line: #{view.name}
29
+ You can also navigate to the others.
30
+ Total of 13 posts
31
+ Each post may be in only one view or two or all three
32
+ EOS
33
+
34
+ %w[blog1 blog2 blog3].each do |v|
35
+ @repo.generate_front_page(v)
36
+ end
37
+
38
+ examine view
@@ -0,0 +1,40 @@
1
+ require_relative './environment'
2
+
3
+ manual_setup
4
+
5
+ srand(42) # for random posts
6
+
7
+ create_3_views
8
+ create_13_posts_manual
9
+ alter_pubdates
10
+
11
+ view = @repo.view("blog3")
12
+ File.open(view.dir/:config/"layout.txt", "w") do |f|
13
+ f.puts "header"
14
+ f.puts "main"
15
+ f.puts "right 20%"
16
+ end
17
+ view.generate_empty_containers
18
+ File.open(view.dir/:config/"right.txt", "w") do |f|
19
+ f.puts "widget links"
20
+ end
21
+
22
+ data = view.dir/:widgets/"links/list.txt"
23
+ Dir.mkdir(view.dir/:widgets/"links")
24
+ File.open(data, "w") do |f|
25
+ f.puts "https://www.google.com,Google"
26
+ f.puts "https://www.yahoo.com,Yahoo"
27
+ end
28
+ see_file data
29
+
30
+ view.generate_front_page
31
+
32
+ instruct <<~EOS
33
+ Again, 13 posts in three views
34
+ blog3 will have only header, main, right
35
+ It will have the Links widget
36
+ Click the + to expand
37
+ Links open in new tabs
38
+ EOS
39
+
40
+ examine view
@@ -0,0 +1,24 @@
1
+ require_relative './environment'
2
+
3
+ manual_setup
4
+
5
+ srand(42) # for random posts
6
+
7
+ view = @repo.create_view("testview", "Another Test View", "testing pagination for post index")
8
+
9
+ 35.times do |i|
10
+ post = @repo.create_post(title: pseudowords(5, "Post #{i}"), body: pseudolines(10))
11
+ post.set_pubdate_with_seconds("2025-07-26", i) # Set seconds to 00, 01, 02, etc.
12
+ @repo.generate_post(post.id)
13
+ end
14
+
15
+ view.generate_front_page
16
+
17
+ instruct <<~EOS
18
+ Creates 35 posts (now instant!)
19
+ Posts have timestamps 12:00:00, 12:00:01, 12:00:02, etc.
20
+ Confirm they are in "recent first" order -- 35 down to 1
21
+ Confirm pagination works
22
+ EOS
23
+
24
+ examine view
@@ -0,0 +1,73 @@
1
+ require_relative './environment'
2
+
3
+ manual_setup
4
+
5
+ srand(42) # for random posts
6
+
7
+ create_3_views
8
+ create_13_posts_manual
9
+ alter_pubdates
10
+
11
+ view = @repo.view("blog3")
12
+ File.open(view.dir/:config/"layout.txt", "w") do |f|
13
+ f.puts "header"
14
+ f.puts "main"
15
+ f.puts "right 20%"
16
+ end
17
+ view.generate_empty_containers
18
+ File.open(view.dir/:config/"right.txt", "w") do |f|
19
+ f.puts "widget links"
20
+ f.puts "widget pages"
21
+ end
22
+
23
+ # Set up the Links widget
24
+ data = view.dir/:widgets/"links/list.txt"
25
+ Dir.mkdir(view.dir/:widgets/"links")
26
+ File.open(data, "w") do |f|
27
+ f.puts "https://www.google.com,Google"
28
+ f.puts "https://www.yahoo.com,Yahoo"
29
+ end
30
+ see_file data
31
+
32
+ # Set up the Pages widget with two dummy pages
33
+ pages_dir = view.dir/:widgets/"pages"
34
+ Dir.mkdir(pages_dir)
35
+
36
+ # Create the list.txt file that the Pages widget reads
37
+ File.open(pages_dir/"list.txt", "w") do |f|
38
+ f.puts "about"
39
+ f.puts "contact"
40
+ end
41
+
42
+ # Create the actual page files
43
+ File.open(view.dir/:pages/"about.html", "w") do |f|
44
+ f.puts "<html><head><title>About Us</title></head><body>"
45
+ f.puts "<h1>About Us</h1>"
46
+ f.puts "<p>Learn more about our company and mission</p>"
47
+ f.puts "<p><a href=\"index.html\">← Back to Home</a></p>"
48
+ f.puts "</body></html>"
49
+ end
50
+ File.open(view.dir/:pages/"contact.html", "w") do |f|
51
+ f.puts "<html><head><title>Contact</title></head><body>"
52
+ f.puts "<h1>Contact</h1>"
53
+ f.puts "<p>Get in touch with our team</p>"
54
+ f.puts "<p><a href=\"index.html\">← Back to Home</a></a></p>"
55
+ f.puts "</body></html>"
56
+ end
57
+
58
+ see_file pages_dir/"list.txt"
59
+ see_file view.dir/:pages/"about.html"
60
+ see_file view.dir/:pages/"contact.html"
61
+
62
+ view.generate_front_page
63
+
64
+ instruct <<~EOS
65
+ Again, 13 posts in three views
66
+ blog3 will have only header, main, right
67
+ It will have both the Links widget and Pages widget in the right sidebar
68
+ Click the + to expand widgets
69
+ Links open in new tabs
70
+ Pages show dummy content (About Us and Contact)
71
+ EOS
72
+
73
+ examine view
@@ -0,0 +1,120 @@
1
+ # Manual inspection tests for BannerSVG feature combinations
2
+ #
3
+ # This file creates posts with sensible combinations of banner features,
4
+ # demonstrating how multiple features work together in realistic scenarios.
5
+ # The posts are displayed in a browser for visual inspection.
6
+ #
7
+ # Usage:
8
+ # ruby test_banner_combinations.rb # Interactive mode with browser
9
+ # ruby test_banner_combinations.rb --automated # Automated mode for CI/AI testing
10
+ #
11
+ # Combinations tested:
12
+ # - Professional Blue: Dark blue background with white bold centered text
13
+ # - Gradient Elegance: Purple gradient with white bold italic centered text
14
+ # - Warm Welcome: Yellow radial gradient with dark text, left-aligned
15
+ # - High Contrast: Black background with large white bold text
16
+ # - Reverse Contrast: White background with black text, right-aligned
17
+ # - Creative Gradient: Diagonal gradient with white bold centered text
18
+ # - Subtle Elegance: Light gray with dark italic text
19
+ # - Bold Statement: Red gradient with large white bold text
20
+ # - Modern Minimal: Light background with smaller dark text
21
+ #
22
+ require_relative "./banner_environment"
23
+
24
+ # Create test banners for sensible combinations
25
+ create_banner_post(
26
+ "Professional Blue",
27
+ "Clean and modern design",
28
+ "back.color #1e3a8a\ntext.color #ffffff\ntitle.style bold\ntext.position center\ntitle.xy 50% 30%\nsubtitle.xy 50% 70%",
29
+ "Professional Blue (White text, bold, centered)",
30
+ "banner-combo-test"
31
+ )
32
+
33
+ create_banner_post(
34
+ "Gradient Elegance",
35
+ "Smooth color transition",
36
+ "back.linear #667eea #764ba2 lr\ntext.color #ffffff\ntitle.style bold italic\ntext.position center\ntitle.xy 50% 30%\nsubtitle.xy 50% 70%",
37
+ "Gradient Elegance (Purple gradient, white text, bold italic, centered)",
38
+ "banner-combo-test"
39
+ )
40
+
41
+ create_banner_post(
42
+ "Warm Welcome",
43
+ "Friendly and inviting",
44
+ "back.radial #fbbf24 #f59e0b\ntext.color #1f2937\ntitle.style bold\ntext.position left\ntitle.xy 10% 30%\nsubtitle.xy 10% 70%",
45
+ "Warm Welcome (Yellow radial, dark text, bold, left-aligned)",
46
+ "banner-combo-test"
47
+ )
48
+
49
+ create_banner_post(
50
+ "High Contrast",
51
+ "Maximum readability",
52
+ "back.color #000000\ntext.color #ffffff\ntitle.style bold\ntitle.scale 1.2\nsubtitle.scale 0.8\ntext.position center\ntitle.xy 50% 30%\nsubtitle.xy 50% 70%",
53
+ "High Contrast (Black background, white text, bold, large, centered)",
54
+ "banner-combo-test"
55
+ )
56
+
57
+ create_banner_post(
58
+ "Reverse Contrast",
59
+ "Inverted color scheme",
60
+ "back.color #ffffff\ntext.color #000000\ntitle.style bold\ntext.position right\ntitle.xy 90% 30%\nsubtitle.xy 90% 70%",
61
+ "Reverse Contrast (White background, black text, bold, right-aligned)",
62
+ "banner-combo-test"
63
+ )
64
+
65
+ create_banner_post(
66
+ "Creative Gradient",
67
+ "Diagonal color flow",
68
+ "back.linear #ff6b6b #4ecdc4 ul-lr\ntext.color #ffffff\ntitle.style bold\ntitle.scale 1.1\nsubtitle.scale 0.7\ntext.position center\ntitle.xy 50% 30%\nsubtitle.xy 50% 70%",
69
+ "Creative Gradient (Diagonal gradient, white text, bold, centered)",
70
+ "banner-combo-test"
71
+ )
72
+
73
+ create_banner_post(
74
+ "Subtle Elegance",
75
+ "Understated beauty",
76
+ "back.color #f8fafc\ntext.color #475569\ntitle.style italic\ntext.position center\ntitle.xy 50% 35%\nsubtitle.xy 50% 75%",
77
+ "Subtle Elegance (Light gray background, dark text, italic, centered)",
78
+ "banner-combo-test"
79
+ )
80
+
81
+ create_banner_post(
82
+ "Bold Statement",
83
+ "Make an impact",
84
+ "back.linear #dc2626 #7c2d12 tb\ntext.color #ffffff\ntitle.style bold\ntitle.scale 1.3\nsubtitle.scale 0.9\ntext.position center\ntitle.xy 50% 25%\nsubtitle.xy 50% 75%",
85
+ "Bold Statement (Red gradient, white text, bold, large, centered)",
86
+ "banner-combo-test"
87
+ )
88
+
89
+ create_banner_post(
90
+ "Modern Minimal",
91
+ "Clean and simple",
92
+ "back.color #f1f5f9\ntext.color #0f172a\ntitle.style bold\ntitle.scale 0.9\nsubtitle.scale 0.6\ntext.position left\ntitle.xy 5% 40%\nsubtitle.xy 5% 80%",
93
+ "Modern Minimal (Light background, dark text, bold, left-aligned, smaller)",
94
+ "banner-combo-test"
95
+ )
96
+
97
+ generate_front_page("banner-combo-test")
98
+
99
+ instruct <<~EOS
100
+ BannerSVG Combination Tests
101
+
102
+ This page displays posts with sensible feature combinations:
103
+ - Professional Blue: Dark blue background with white bold centered text
104
+ - Gradient Elegance: Purple gradient with white bold italic centered text
105
+ - Warm Welcome: Yellow radial gradient with dark text, left-aligned
106
+ - High Contrast: Black background with large white bold text
107
+ - Reverse Contrast: White background with black text, right-aligned
108
+ - Creative Gradient: Diagonal gradient with white bold centered text
109
+ - Subtle Elegance: Light gray with dark italic text
110
+ - Bold Statement: Red gradient with large white bold text
111
+ - Modern Minimal: Light background with smaller dark text
112
+
113
+ Each combination shows how multiple features work together.
114
+ Check that gradients render properly, text positioning is correct,
115
+ and the overall design looks cohesive and professional.
116
+
117
+ The JavaScript should handle dynamic resizing when you resize the browser window.
118
+ EOS
119
+
120
+ examine("banner-combo-test")
@@ -0,0 +1,306 @@
1
+ # Manual inspection tests for BannerSVG features
2
+ #
3
+ # This file creates individual HTML pages for each banner feature test,
4
+ # with simple navigation between them. Each page is completely isolated
5
+ # to prevent state sharing issues.
6
+ #
7
+ # Usage:
8
+ # ruby test_banner_features_simple.rb # Interactive mode with browser
9
+ # ruby test_banner_features_simple.rb --automated # Automated mode for CI/AI testing
10
+ #
11
+ require_relative "../../lib/scriptorium"
12
+ require_relative "./banner_environment"
13
+
14
+ # Test definitions
15
+ tests = [
16
+ {
17
+ title: "Red Background",
18
+ subtitle: "Solid color test",
19
+ config: "back.color #ff0000",
20
+ description: "Red Background"
21
+ },
22
+ {
23
+ title: "Blue Background",
24
+ subtitle: "Solid color test",
25
+ config: "back.color #0000ff",
26
+ description: "Blue Background"
27
+ },
28
+ {
29
+ title: "Green Background",
30
+ subtitle: "Solid color test",
31
+ config: "back.color #00ff00",
32
+ description: "Green Background"
33
+ },
34
+ {
35
+ title: "Red to Blue Gradient",
36
+ subtitle: "Linear gradient test",
37
+ config: "back.linear red blue lr",
38
+ description: "Linear Gradient (Left to Right)"
39
+ },
40
+ {
41
+ title: "Green to Yellow Gradient",
42
+ subtitle: "Linear gradient test",
43
+ config: "back.linear green yellow tb",
44
+ description: "Linear Gradient (Top to Bottom)"
45
+ },
46
+ {
47
+ title: "Red to Blue Radial",
48
+ subtitle: "Radial gradient test",
49
+ config: "back.radial red blue",
50
+ description: "Radial Gradient"
51
+ },
52
+ {
53
+ title: "Green to Yellow Radial",
54
+ subtitle: "Radial gradient test",
55
+ config: "back.radial green yellow",
56
+ description: "Radial Gradient"
57
+ },
58
+ {
59
+ title: "Small Text",
60
+ subtitle: "Size test",
61
+ config: "title.scale 0.5\nsubtitle.scale 0.3",
62
+ description: "Small Text (0.5x, 0.3x)"
63
+ },
64
+ {
65
+ title: "Large Text",
66
+ subtitle: "Size test",
67
+ config: "title.scale 1.5\nsubtitle.scale 1.0",
68
+ description: "Large Text (1.5x, 1.0x)"
69
+ },
70
+ {
71
+ title: "Bold Text",
72
+ subtitle: "Style test",
73
+ config: "title.style bold\nsubtitle.style bold",
74
+ description: "Bold Text"
75
+ },
76
+ {
77
+ title: "Italic Text",
78
+ subtitle: "Style test",
79
+ config: "title.style italic\nsubtitle.style italic",
80
+ description: "Italic Text"
81
+ },
82
+ {
83
+ title: "Bold & Italic",
84
+ subtitle: "Style test",
85
+ config: "title.style bold italic\nsubtitle.style bold italic",
86
+ description: "Bold & Italic Text"
87
+ },
88
+ {
89
+ title: "Blue Text",
90
+ subtitle: "Color test",
91
+ config: "title.color #0000ff\nsubtitle.color #0000ff",
92
+ description: "Blue Text"
93
+ },
94
+ {
95
+ title: "Green Text",
96
+ subtitle: "Color test",
97
+ config: "title.color #00ff00\nsubtitle.color #00ff00",
98
+ description: "Green Text"
99
+ },
100
+ {
101
+ title: "Left Position",
102
+ subtitle: "Position test",
103
+ config: "text.align left",
104
+ description: "Left Positioned Text"
105
+ },
106
+ {
107
+ title: "Center Position",
108
+ subtitle: "Position test",
109
+ config: "text.align center",
110
+ description: "Center Positioned Text"
111
+ },
112
+ {
113
+ title: "Right Position",
114
+ subtitle: "Position test",
115
+ config: "text.align right",
116
+ description: "Right Positioned Text"
117
+ },
118
+ {
119
+ title: "Perfect Image Background",
120
+ subtitle: "Image test (8:1 aspect)",
121
+ config: "back.image ../../assets/images/perfect.png",
122
+ description: "Perfect match: 8:1 aspect ratio image fits banner exactly - no cropping or scaling needed"
123
+ },
124
+ {
125
+ title: "Wide Image Background",
126
+ subtitle: "Image test (16:1 aspect)",
127
+ config: "back.image ../../assets/images/wide.png",
128
+ description: "Wide image (16:1) cropped to fit 8:1 banner - left/right edges removed, center preserved"
129
+ },
130
+ {
131
+ title: "Tall Image Background",
132
+ subtitle: "Image test (1:1 aspect)",
133
+ config: "back.image ../../assets/images/tall.png",
134
+ description: "Square image (1:1) cropped to fit 8:1 banner - top/bottom removed, center strip visible"
135
+ },
136
+ {
137
+ title: "Very Tall Image Background",
138
+ subtitle: "Image test (1:4 aspect)",
139
+ config: "back.image ../../assets/images/very_tall.png",
140
+ description: "Very tall image (1:4) heavily cropped - only narrow center strip visible, most content lost"
141
+ },
142
+ {
143
+ title: "Very Wide Image Background",
144
+ subtitle: "Image test (16:1 aspect)",
145
+ config: "back.image ../../assets/images/very_wide.png",
146
+ description: "Very wide image (16:1) heavily cropped - only narrow center strip visible, sides removed"
147
+ },
148
+ {
149
+ title: "Small Image Background",
150
+ subtitle: "Image test (low res, 8:1 aspect)",
151
+ config: "back.image ../../assets/images/small.png",
152
+ description: "Small low-res image scaled up to fill banner - may appear pixelated but maintains aspect"
153
+ },
154
+ {
155
+ title: "Odd Aspect Image Background",
156
+ subtitle: "Image test (~4:1 aspect)",
157
+ config: "back.image ../../assets/images/odd_aspect.png",
158
+ description: "Non-standard aspect ratio (~4:1) cropped to fit 8:1 banner - moderate cropping applied"
159
+ },
160
+ {
161
+ title: "Another gradient test",
162
+ subtitle: "Just one more, I swear",
163
+ config: "back.linear #0000ff #000033 lr\ntitle.color #fff\nsubtitle.color #fff",
164
+ description: "Linear Gradient (Left to Right)"
165
+ }
166
+ ]
167
+
168
+ # Create temp directory for tests
169
+ test_dir = File.dirname(__FILE__)/"banner-tests"
170
+ Dir.mkdir(test_dir) unless Dir.exist?(test_dir)
171
+
172
+ # Create individual pages for each test
173
+ pages = []
174
+ tests.each_with_index do |test, index|
175
+ page_num = index + 1
176
+ filename = "test#{page_num.to_s.rjust(2, '0')}.html"
177
+
178
+ # Write config file for this test
179
+ File.write(test_dir/"config.txt", test[:config])
180
+
181
+ # Create banner
182
+ require_relative '../../lib/scriptorium'
183
+ Dir.chdir(test_dir) do
184
+ banner = Scriptorium::BannerSVG.new(test[:title], test[:subtitle])
185
+ banner.parse_header_svg
186
+ svg_output = banner.generate_svg
187
+
188
+ # Check if this is an image background test
189
+ image_path = nil
190
+ if test[:config].include?("back.image")
191
+ image_path = test[:config].match(/back\.image\s+(.+)/)&.[](1)
192
+ # For the original image display, we need the path relative to the HTML file
193
+ # The HTML is in test/manual/banner-tests/, and images are now in the same directory
194
+ # So browser URL should be just the filename (relative to HTML file)
195
+ display_path = image_path.gsub('../../assets/images/', '') if image_path
196
+
197
+ # Fix the SVG pattern path to use the correct relative path for the HTML file
198
+ svg_output = svg_output.gsub('../../assets/images/', '')
199
+ end
200
+
201
+ # Create standalone HTML page
202
+ html_content = <<~HTML
203
+ <!DOCTYPE html>
204
+ <html>
205
+ <head>
206
+ <title>#{test[:title]}</title>
207
+ <style>
208
+ body { font-family: Arial, sans-serif; margin: 0; padding: 0; background: #f5f5f5; }
209
+ .banner { width: 100%; margin: 0; padding: 0; border: 3px solid #007cba; border-radius: 8px; }
210
+ .content { padding: 20px; padding-bottom: 80px; }
211
+ .description { margin: 10px 0; font-weight: bold; }
212
+ .config { background: #f0f0f0; padding: 10px; margin: 10px 0; font-family: monospace; font-size: 12px; }
213
+ .navigation {
214
+ position: fixed;
215
+ bottom: 0;
216
+ left: 0;
217
+ right: 0;
218
+ background: #e0e0e0;
219
+ padding: 15px;
220
+ text-align: center;
221
+ border-top: 2px solid #007cba;
222
+ z-index: 1000;
223
+ }
224
+ .navigation a { margin: 0 10px; padding: 8px 15px; background: #007cba; color: white; text-decoration: none; border-radius: 3px; }
225
+ .navigation a:hover { background: #005a87; }
226
+ .original-image { margin: 20px 0; padding: 20px; background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
227
+ .original-image h3 { margin: 0 0 10px 0; color: #333; }
228
+ .original-image img { max-width: 100%; height: auto; border: 1px solid #ddd; }
229
+ </style>
230
+ </head>
231
+ <body>
232
+ <div class="banner">
233
+ #{svg_output}
234
+ </div>
235
+ <div class="content">
236
+ <div class="description">#{test[:description]}</div>
237
+ <div class="config">#{test[:config]}</div>
238
+ #{image_path ? "<div class='original-image'>\n <h3>Original Image (for comparison):</h3>\n <img src='#{display_path}' alt='Original image'>\n </div>" : ""}
239
+ <div class="navigation">
240
+ <a href="index.html">Back to Index</a>
241
+ </div>
242
+ </div>
243
+ </body>
244
+ </html>
245
+ HTML
246
+
247
+ File.write(filename, html_content)
248
+ end
249
+
250
+ pages << { number: page_num, title: test[:title], filename: filename }
251
+ end
252
+
253
+ # Add navigation links to each page
254
+ pages.each_with_index do |page, index|
255
+ prev_page = index > 0 ? pages[index - 1][:filename] : nil
256
+ next_page = index < pages.length - 1 ? pages[index + 1][:filename] : nil
257
+
258
+ # Read the current page
259
+ page_file = test_dir/page[:filename]
260
+ content = File.read(page_file)
261
+
262
+ # Create navigation HTML
263
+ nav_html = '<div class="navigation">'
264
+ nav_html += '<a href="index.html">Back to Index</a>'
265
+ nav_html += " <a href=\"#{prev_page}\">Previous</a>" if prev_page
266
+ nav_html += " <a href=\"#{next_page}\">Next</a>" if next_page
267
+ nav_html += '</div>'
268
+
269
+ # Replace the placeholder navigation
270
+ content.gsub!(/<div class="navigation">.*?<\/div>/m, nav_html)
271
+
272
+ # Write the updated page
273
+ File.write(page_file, content)
274
+ end
275
+
276
+ # Create index page
277
+ index_html = <<~HTML
278
+ <!DOCTYPE html>
279
+ <html>
280
+ <head>
281
+ <title>BannerSVG Feature Tests</title>
282
+ <style>
283
+ body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
284
+ .test-list { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
285
+ .test-item { margin: 10px 0; padding: 10px; background: #f9f9f9; border-left: 4px solid #007cba; }
286
+ .test-item a { color: #007cba; text-decoration: none; font-weight: bold; }
287
+ .test-item a:hover { text-decoration: underline; }
288
+ .test-description { color: #666; font-size: 14px; margin-top: 5px; }
289
+ </style>
290
+ </head>
291
+ <body>
292
+ <h1>BannerSVG Feature Tests</h1>
293
+ <div class="test-list">
294
+ <p>Click on any test to view the banner in isolation:</p>
295
+ #{pages.map.with_index { |page, index|
296
+ "<div class='test-item'><a href='#{page[:filename]}'>#{index + 1}. #{page[:title]}</a><div class='test-description'>#{tests[index][:description]}</div></div>"
297
+ }.join("\n")}
298
+ </div>
299
+ </body>
300
+ </html>
301
+ HTML
302
+
303
+ File.write(test_dir/"index.html", index_html)
304
+
305
+ # Call the environment's examine function
306
+ examine("banner-test")