scriptorium 0.0.3 → 0.7.2

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 (353) 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/icons/social/reddit.png +0 -0
  7. data/assets/icons/social/x-logo.png +0 -0
  8. data/assets/icons/ui/.DS_Store +0 -0
  9. data/assets/icons/ui/back.png +0 -0
  10. data/assets/icons/ui/copy.png +0 -0
  11. data/assets/icons/ui/down.png +0 -0
  12. data/assets/icons/ui/end.png +0 -0
  13. data/assets/icons/ui/exit.png +0 -0
  14. data/assets/icons/ui/foo +10 -0
  15. data/assets/icons/ui/home.png +0 -0
  16. data/assets/icons/ui/left.png +0 -0
  17. data/assets/icons/ui/next.png +0 -0
  18. data/assets/icons/ui/right.png +0 -0
  19. data/assets/icons/ui/start.png +0 -0
  20. data/assets/icons/ui/up.png +0 -0
  21. data/assets/imagenotfound.jpg +0 -0
  22. data/assets/samples/placeholder.svg +9 -0
  23. data/assets/themes/standard/favicon.svg +6 -0
  24. data/bin/sblog +84 -5
  25. data/bin/scriptorium +1 -0
  26. data/doc/README.txt +6 -0
  27. data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +94 -0
  28. data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +2 -0
  29. data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +45 -0
  30. data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +40 -0
  31. data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +46 -0
  32. data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +158 -0
  33. data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +35 -0
  34. data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +27 -0
  35. data/doc/anti-amnesia/20250807-213025.md +116 -0
  36. data/doc/anti-amnesia/20250901-211714-codemirror-integration-and-web-tests.md +172 -0
  37. data/doc/anti-amnesia/20250902-002402-backup-restore-system.md +126 -0
  38. data/doc/anti-amnesia/20250907-203339-backup-metadata-implementation.md +66 -0
  39. data/doc/banner_svg_config.md +114 -0
  40. data/doc/contrib.lt3 +8 -0
  41. data/doc/dependencies.md +281 -0
  42. data/doc/hacker.lt3 +5 -0
  43. data/doc/imported/0001-elixir-conf-2014/metadata.txt +7 -0
  44. data/doc/imported/0001-elixir-conf-2014/post.html +37 -0
  45. data/doc/imported/0001-elixir-conf-2014/source.lt3 +22 -0
  46. data/doc/imported/0002-programmers-and-word-processing/metadata.txt +7 -0
  47. data/doc/imported/0002-programmers-and-word-processing/post.html +192 -0
  48. data/doc/imported/0002-programmers-and-word-processing/source.lt3 +146 -0
  49. data/doc/imported/0003-how-to-turn-your-brain-sideways/metadata.txt +7 -0
  50. data/doc/imported/0003-how-to-turn-your-brain-sideways/post.html +60 -0
  51. data/doc/imported/0003-how-to-turn-your-brain-sideways/source.lt3 +40 -0
  52. data/doc/imported/0004-upcoming-lone-star-ruby-conference/metadata.txt +7 -0
  53. data/doc/imported/0004-upcoming-lone-star-ruby-conference/post.html +42 -0
  54. data/doc/imported/0004-upcoming-lone-star-ruby-conference/source.lt3 +24 -0
  55. data/doc/imported/0005-elixir-conf-2015-announced/metadata.txt +7 -0
  56. data/doc/imported/0005-elixir-conf-2015-announced/post.html +30 -0
  57. data/doc/imported/0005-elixir-conf-2015-announced/source.lt3 +16 -0
  58. data/doc/imported/0006-ruby-for-dinosaurs/metadata.txt +7 -0
  59. data/doc/imported/0006-ruby-for-dinosaurs/post.html +43 -0
  60. data/doc/imported/0006-ruby-for-dinosaurs/source.lt3 +27 -0
  61. data/doc/imported/0007-phoenix-isnt-rails/metadata.txt +7 -0
  62. data/doc/imported/0007-phoenix-isnt-rails/post.html +116 -0
  63. data/doc/imported/0007-phoenix-isnt-rails/source.lt3 +87 -0
  64. data/doc/imported/0008-concerning-the-term-monkeypatching/metadata.txt +7 -0
  65. data/doc/imported/0008-concerning-the-term-monkeypatching/post.html +129 -0
  66. data/doc/imported/0008-concerning-the-term-monkeypatching/source.lt3 +92 -0
  67. data/doc/imported/0009-announcement-coming-soon/metadata.txt +7 -0
  68. data/doc/imported/0009-announcement-coming-soon/post.html +33 -0
  69. data/doc/imported/0009-announcement-coming-soon/source.lt3 +19 -0
  70. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/metadata.txt +7 -0
  71. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/post.html +175 -0
  72. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/source.lt3 +139 -0
  73. data/doc/imported/0011-computer-science-as-a-lost-art/metadata.txt +7 -0
  74. data/doc/imported/0011-computer-science-as-a-lost-art/post.html +139 -0
  75. data/doc/imported/0011-computer-science-as-a-lost-art/source.lt3 +104 -0
  76. data/doc/imported/0012-ruby-day-in-turin-italy/metadata.txt +7 -0
  77. data/doc/imported/0012-ruby-day-in-turin-italy/post.html +42 -0
  78. data/doc/imported/0012-ruby-day-in-turin-italy/source.lt3 +24 -0
  79. data/doc/imported/0013-rubyday-was-a-success/metadata.txt +7 -0
  80. data/doc/imported/0013-rubyday-was-a-success/post.html +44 -0
  81. data/doc/imported/0013-rubyday-was-a-success/source.lt3 +27 -0
  82. data/doc/imported/0014-working-on-the-blogging-software/metadata.txt +7 -0
  83. data/doc/imported/0014-working-on-the-blogging-software/post.html +63 -0
  84. data/doc/imported/0014-working-on-the-blogging-software/source.lt3 +41 -0
  85. data/doc/imported/0015-ok-its-not-really-a-lost-art/metadata.txt +7 -0
  86. data/doc/imported/0015-ok-its-not-really-a-lost-art/post.html +172 -0
  87. data/doc/imported/0015-ok-its-not-really-a-lost-art/source.lt3 +134 -0
  88. data/doc/imported/0016-an-in-operator-for-ruby/metadata.txt +7 -0
  89. data/doc/imported/0016-an-in-operator-for-ruby/post.html +155 -0
  90. data/doc/imported/0016-an-in-operator-for-ruby/source.lt3 +106 -0
  91. data/doc/imported/0017-the-forgotten-mathematician/metadata.txt +7 -0
  92. data/doc/imported/0017-the-forgotten-mathematician/post.html +161 -0
  93. data/doc/imported/0017-the-forgotten-mathematician/source.lt3 +119 -0
  94. data/doc/imported/0018-ruby-puns/metadata.txt +7 -0
  95. data/doc/imported/0018-ruby-puns/post.html +46 -0
  96. data/doc/imported/0018-ruby-puns/source.lt3 +28 -0
  97. data/doc/imported/0019-custom-exceptions-via-metaprogramming/metadata.txt +7 -0
  98. data/doc/imported/0019-custom-exceptions-via-metaprogramming/post.html +138 -0
  99. data/doc/imported/0019-custom-exceptions-via-metaprogramming/source.lt3 +101 -0
  100. data/doc/imported/0020-fffff/metadata.txt +7 -0
  101. data/doc/imported/0020-fffff/post.html +24 -0
  102. data/doc/imported/0020-fffff/source.lt3 +12 -0
  103. data/doc/imported/0021-trying-ror-yet-again/metadata.txt +7 -0
  104. data/doc/imported/0021-trying-ror-yet-again/post.html +26 -0
  105. data/doc/imported/0021-trying-ror-yet-again/source.lt3 +12 -0
  106. data/doc/imported/0023-doctor-sleep/metadata.txt +7 -0
  107. data/doc/imported/0023-doctor-sleep/post.html +63 -0
  108. data/doc/imported/0023-doctor-sleep/source.lt3 +44 -0
  109. data/doc/imported/0024-just-a-test/metadata.txt +7 -0
  110. data/doc/imported/0024-just-a-test/post.html +24 -0
  111. data/doc/imported/0024-just-a-test/source.lt3 +12 -0
  112. data/doc/imported/import_summary.txt +98 -0
  113. data/doc/livetext-informal-spec.txt +65 -0
  114. data/doc/myuserdoc/ch-0.lt3 +31 -0
  115. data/doc/myuserdoc/ch-1.lt3 +37 -0
  116. data/doc/myuserdoc/ch-10.lt3 +22 -0
  117. data/doc/myuserdoc/ch-2.lt3 +37 -0
  118. data/doc/myuserdoc/ch-3.lt3 +19 -0
  119. data/doc/myuserdoc/ch-4.lt3 +43 -0
  120. data/doc/myuserdoc/ch-5.lt3 +22 -0
  121. data/doc/myuserdoc/ch-6.lt3 +19 -0
  122. data/doc/myuserdoc/ch-7.lt3 +16 -0
  123. data/doc/myuserdoc/ch-8.lt3 +13 -0
  124. data/doc/myuserdoc/ch-9.lt3 +19 -0
  125. data/doc/myuserdoc/tweak.rb +18 -0
  126. data/doc/myuserdoc/userdoc-toc.txt +88 -0
  127. data/doc/old-posts/0001-elixir-conf-2014.lt3 +24 -0
  128. data/doc/old-posts/0002-programmers-and-word-processing.lt3 +150 -0
  129. data/doc/old-posts/0003-how-to-turn-your-brain-sideways.lt3 +43 -0
  130. data/doc/old-posts/0004-upcoming-lone-star-ruby-conference.lt3 +26 -0
  131. data/doc/old-posts/0005-elixir-conf-2015-announced.lt3 +17 -0
  132. data/doc/old-posts/0006-ruby-for-dinosaurs.lt3 +30 -0
  133. data/doc/old-posts/0007-phoenix-isnt-rails.lt3 +90 -0
  134. data/doc/old-posts/0008-concerning-the-term-monkeypatching.lt3 +105 -0
  135. data/doc/old-posts/0009-announcement-coming-soon.lt3 +20 -0
  136. data/doc/old-posts/0010-immutable-data-ditching-the-wax-tablet.lt3 +142 -0
  137. data/doc/old-posts/0011-computer-science-as-a-lost-art.lt3 +117 -0
  138. data/doc/old-posts/0012-ruby-day-in-turin-italy.lt3 +26 -0
  139. data/doc/old-posts/0013-rubyday-was-a-success.lt3 +28 -0
  140. data/doc/old-posts/0014-working-on-the-blogging-software.lt3 +42 -0
  141. data/doc/old-posts/0015-ok-its-not-really-a-lost-art.lt3 +137 -0
  142. data/doc/old-posts/0016-an-in-operator-for-ruby.lt3 +142 -0
  143. data/doc/old-posts/0017-the-forgotten-mathematician.lt3 +129 -0
  144. data/doc/old-posts/0018-ruby-puns.lt3 +31 -0
  145. data/doc/old-posts/0019-custom-exceptions-via-metaprogramming.lt3 +116 -0
  146. data/doc/old-posts/0021-trying-ror-yet-again.lt3 +35 -0
  147. data/doc/old-posts/0023-doctor-sleep.lt3 +43 -0
  148. data/doc/old-posts/0024-just-a-test.lt3 +12 -0
  149. data/doc/old-posts/0025-trying-another-post.lt3 +12 -0
  150. data/doc/old-repo +1 -0
  151. data/doc/reddit_credentials_template.json +8 -0
  152. data/doc/reddit_integration.md +207 -0
  153. data/doc/user.lt3 +35 -0
  154. data/doc/user_guide_section_1.md +137 -0
  155. data/doc/user_guide_section_10.md +515 -0
  156. data/doc/user_guide_section_11.md +708 -0
  157. data/doc/user_guide_section_2.md +233 -0
  158. data/doc/user_guide_section_3.md +5 -0
  159. data/doc/user_guide_section_4.md +221 -0
  160. data/doc/user_guide_section_5.md +243 -0
  161. data/doc/user_guide_section_6.md +147 -0
  162. data/doc/user_guide_section_7.md +311 -0
  163. data/doc/user_guide_section_8.md +224 -0
  164. data/doc/user_guide_section_9.md +375 -0
  165. data/lib/rouge/lexers/livetext.rb +74 -0
  166. data/lib/scriptorium/api.rb +2373 -0
  167. data/lib/scriptorium/banner_svg.rb +729 -0
  168. data/lib/scriptorium/contract.rb +34 -0
  169. data/lib/scriptorium/exceptions.rb +201 -1
  170. data/lib/scriptorium/helpers.rb +675 -0
  171. data/lib/scriptorium/post.rb +259 -0
  172. data/lib/scriptorium/reddit.rb +83 -0
  173. data/lib/scriptorium/repo.rb +938 -0
  174. data/lib/scriptorium/standard_files.rb +149 -0
  175. data/lib/scriptorium/support/bootstrap/css.txt +5 -0
  176. data/lib/scriptorium/support/bootstrap/js.txt +4 -0
  177. data/lib/scriptorium/support/common_js/clipboard.js +35 -0
  178. data/lib/scriptorium/support/common_js/content-loader.js +187 -0
  179. data/lib/scriptorium/support/common_js/navigation.js +52 -0
  180. data/lib/scriptorium/support/common_js/syntax-highlighting.js +27 -0
  181. data/lib/scriptorium/support/config/reddit.txt +10 -0
  182. data/lib/scriptorium/support/config/reddit_template.txt +17 -0
  183. data/lib/scriptorium/support/config/social.txt +8 -0
  184. data/lib/scriptorium/support/highlight/css.txt +2 -0
  185. data/lib/scriptorium/support/highlight/custom.css +119 -0
  186. data/lib/scriptorium/support/highlight/js.txt +1 -0
  187. data/lib/scriptorium/support/post_index/config.txt +15 -0
  188. data/lib/scriptorium/support/post_index/style.css +55 -0
  189. data/lib/scriptorium/support/templates/index_entry.lt3 +16 -0
  190. data/lib/scriptorium/support/templates/initial_post.lt3 +12 -0
  191. data/lib/scriptorium/support/templates/layout.txt +5 -0
  192. data/lib/scriptorium/support/templates/post.lt3 +104 -0
  193. data/lib/scriptorium/support/theme/footer.lt3 +2 -0
  194. data/lib/scriptorium/support/theme/header.lt3 +4 -0
  195. data/lib/scriptorium/support/theme/left.lt3 +3 -0
  196. data/lib/scriptorium/support/theme/main.lt3 +5 -0
  197. data/lib/scriptorium/support/theme/right.lt3 +3 -0
  198. data/lib/scriptorium/theme.rb +192 -0
  199. data/lib/scriptorium/version.rb +1 -1
  200. data/lib/scriptorium/view.rb +1021 -0
  201. data/lib/scriptorium/widgets/featured_posts.rb +149 -0
  202. data/lib/scriptorium/widgets/links.rb +112 -0
  203. data/lib/scriptorium/widgets/pages.rb +133 -0
  204. data/lib/scriptorium/widgets/widget.rb +133 -0
  205. data/lib/scriptorium.rb +38 -34
  206. data/lib/skeleton.rb +10 -1
  207. data/scriptorium.gemspec +17 -5
  208. data/test/README.md +69 -0
  209. data/test/WEB_INTEGRATION_README.md +196 -0
  210. data/test/all +83 -0
  211. data/test/api_demo.rb +99 -0
  212. data/test/assets/imagenotfound.jpg +0 -0
  213. data/test/assets/images/.DS_Store +0 -0
  214. data/test/assets/images/README.md +27 -0
  215. data/test/assets/images/odd_aspect.png +0 -0
  216. data/test/assets/images/perfect.png +0 -0
  217. data/test/assets/images/small.png +0 -0
  218. data/test/assets/images/tall.png +0 -0
  219. data/test/assets/images/very_tall.png +0 -0
  220. data/test/assets/images/very_wide.png +0 -0
  221. data/test/assets/images/wide.png +0 -0
  222. data/test/assets/testbanner.jpg +0 -0
  223. data/test/banner_svg/simple_helpers.rb +13 -0
  224. data/test/banner_svg/unit.rb +1000 -0
  225. data/test/config/deployment.txt +5 -0
  226. data/test/ed_test.rb +204 -0
  227. data/test/integration/cursor_banner_combinations.rb +193 -0
  228. data/test/integration/cursor_banner_features.rb +374 -0
  229. data/test/integration/integration_test.rb +326 -0
  230. data/test/integration/preview_flow_test.rb +94 -0
  231. data/test/livetext_plugin_test.rb +500 -0
  232. data/test/manual/asset_mgmt.rb +67 -0
  233. data/test/manual/banner-tests/index.html +45 -0
  234. data/test/manual/banner-tests/svg.txt +3 -0
  235. data/test/manual/banner-tests/test01.html +122 -0
  236. data/test/manual/banner-tests/test02.html +122 -0
  237. data/test/manual/banner-tests/test03.html +122 -0
  238. data/test/manual/banner-tests/test04.html +129 -0
  239. data/test/manual/banner-tests/test05.html +129 -0
  240. data/test/manual/banner-tests/test06.html +129 -0
  241. data/test/manual/banner-tests/test07.html +129 -0
  242. data/test/manual/banner-tests/test08.html +123 -0
  243. data/test/manual/banner-tests/test09.html +123 -0
  244. data/test/manual/banner-tests/test10.html +123 -0
  245. data/test/manual/banner-tests/test11.html +123 -0
  246. data/test/manual/banner-tests/test12.html +123 -0
  247. data/test/manual/banner-tests/test13.html +123 -0
  248. data/test/manual/banner-tests/test14.html +123 -0
  249. data/test/manual/banner-tests/test15.html +122 -0
  250. data/test/manual/banner-tests/test16.html +122 -0
  251. data/test/manual/banner-tests/test17.html +122 -0
  252. data/test/manual/banner-tests/test18.html +132 -0
  253. data/test/manual/banner-tests/test19.html +132 -0
  254. data/test/manual/banner-tests/test20.html +132 -0
  255. data/test/manual/banner-tests/test21.html +132 -0
  256. data/test/manual/banner-tests/test22.html +132 -0
  257. data/test/manual/banner-tests/test23.html +132 -0
  258. data/test/manual/banner-tests/test24.html +132 -0
  259. data/test/manual/banner-tests/test25.html +131 -0
  260. data/test/manual/banner_environment.rb +205 -0
  261. data/test/manual/codemirror_demo.html +773 -0
  262. data/test/manual/create_posts_for_web.rb +114 -0
  263. data/test/manual/environment.rb +67 -0
  264. data/test/manual/make_banner.rb +153 -0
  265. data/test/manual/preview_manual_test.rb +129 -0
  266. data/test/manual/sample_banner_config.txt +12 -0
  267. data/test/manual/test_advanced_widgets.rb +73 -0
  268. data/test/manual/test_banner_combinations.rb +120 -0
  269. data/test/manual/test_banner_features.rb +306 -0
  270. data/test/manual/test_banner_integration.rb +115 -0
  271. data/test/manual/test_banner_radial.rb +87 -0
  272. data/test/manual/test_basic_posts.rb +47 -0
  273. data/test/manual/test_layout_widgets.rb +40 -0
  274. data/test/manual/test_pagination.rb +24 -0
  275. data/test/manual/test_random_posts.rb +38 -0
  276. data/test/manual/test_syntax_highlighting.rb +167 -0
  277. data/test/rubytext/rubytext_comprehensive_test.rb +307 -0
  278. data/test/rubytext/rubytext_demo_test.rb +42 -0
  279. data/test/rubytext/rubytext_testing_guide.md +277 -0
  280. data/test/run_automated_tests.rb +45 -0
  281. data/test/staging/.DS_Store +0 -0
  282. data/test/support/preview_utils.rb +88 -0
  283. data/test/syntax_highlighting_test.lt3 +124 -0
  284. data/test/test_gem_assets.rb +48 -0
  285. data/test/test_helpers.rb +240 -0
  286. data/test/tui_editor_integration_test.rb +296 -0
  287. data/test/tui_integration_test.rb +883 -0
  288. data/test/unit/api.rb +1776 -0
  289. data/test/unit/asset_management.rb +219 -0
  290. data/test/unit/backup_test.rb +451 -0
  291. data/test/unit/clipboard_test.rb +60 -0
  292. data/test/unit/contract_test.rb +69 -0
  293. data/test/unit/core.rb +1211 -0
  294. data/test/unit/deploy_config_test.rb +248 -0
  295. data/test/unit/deploy_test.rb +478 -0
  296. data/test/unit/edit_post_test.rb +168 -0
  297. data/test/unit/gem_asset_management.rb +183 -0
  298. data/test/unit/livetext_basic.rb +57 -0
  299. data/test/unit/livetext_compatibility.rb +82 -0
  300. data/test/unit/parse_cmd_test.rb +260 -0
  301. data/test/unit/permalink_copy_test.rb +211 -0
  302. data/test/unit/post.rb +309 -0
  303. data/test/unit/post_index_config_test.rb +258 -0
  304. data/test/unit/post_state_helpers_test.rb +137 -0
  305. data/test/unit/read_commented_file_test.rb +278 -0
  306. data/test/unit/reddit_test.rb +235 -0
  307. data/test/unit/repo.rb +569 -0
  308. data/test/unit/social_test.rb +366 -0
  309. data/test/unit/syntax_highlighting.rb +70 -0
  310. data/test/unit/theme_management_test.rb +91 -0
  311. data/test/unit/view.rb +498 -0
  312. data/test/unit/widgets.rb +669 -0
  313. data/test/web_integration_test.rb +231 -0
  314. data/test/web_test_helper.rb +218 -0
  315. data/test/web_workflow_test.rb +527 -0
  316. data/test/wizard_test.rb +123 -0
  317. data/ui/README.md +67 -0
  318. data/ui/common/lib/ui_common.rb +8 -0
  319. data/ui/rubytext/README.md +191 -0
  320. data/ui/rubytext/bin/scriptorium-rubytext +402 -0
  321. data/ui/rubytext/lib/rubytext_ui.rb +300 -0
  322. data/ui/tui/bin/scriptorium +1890 -0
  323. data/ui/tui/test/tui_test.rb +23 -0
  324. data/ui/web/app/app.rb +2600 -0
  325. data/ui/web/app/assets/livetext_mode.js +244 -0
  326. data/ui/web/app/error_helpers.rb +150 -0
  327. data/ui/web/app/views/advanced_config.erb +196 -0
  328. data/ui/web/app/views/asset_management.erb +645 -0
  329. data/ui/web/app/views/backup_management.erb +238 -0
  330. data/ui/web/app/views/banner_config.erb +200 -0
  331. data/ui/web/app/views/config_widget.erb +232 -0
  332. data/ui/web/app/views/configure_view.erb +401 -0
  333. data/ui/web/app/views/dashboard.erb +154 -0
  334. data/ui/web/app/views/deploy_config.erb +149 -0
  335. data/ui/web/app/views/edit_pages.erb +363 -0
  336. data/ui/web/app/views/edit_post.erb +175 -0
  337. data/ui/web/app/views/edit_theme.erb +73 -0
  338. data/ui/web/app/views/edit_theme_file.erb +74 -0
  339. data/ui/web/app/views/error_page.erb +29 -0
  340. data/ui/web/app/views/header_config.erb +155 -0
  341. data/ui/web/app/views/layout_config.erb +147 -0
  342. data/ui/web/app/views/navbar_config.erb +411 -0
  343. data/ui/web/app/views/theme_management.erb +130 -0
  344. data/ui/web/app/views/view_dashboard.erb +779 -0
  345. data/ui/web/app/views/widgets.erb +249 -0
  346. data/ui/web/bin/scriptorium-web +164 -0
  347. data/ui/web/test/web_basic_test.rb +38 -0
  348. data/ui/web/test_navbar.txt +7 -0
  349. data/ui/web/tmp/timing.log +17 -0
  350. data/ui/web/tmp/web_server.log +0 -0
  351. metadata +434 -8
  352. data/lib/scriptorium/engine.rb +0 -22
  353. data/test/engine/unit.rb +0 -44
@@ -0,0 +1,131 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Another gradient test</title>
5
+ <style>
6
+ body { font-family: Arial, sans-serif; margin: 0; padding: 0; background: #f5f5f5; }
7
+ .banner { width: 100%; margin: 0; padding: 0; border: 3px solid #007cba; border-radius: 8px; }
8
+ .content { padding: 20px; padding-bottom: 80px; }
9
+ .description { margin: 10px 0; font-weight: bold; }
10
+ .config { background: #f0f0f0; padding: 10px; margin: 10px 0; font-family: monospace; font-size: 12px; }
11
+ .navigation {
12
+ position: fixed;
13
+ bottom: 0;
14
+ left: 0;
15
+ right: 0;
16
+ background: #e0e0e0;
17
+ padding: 15px;
18
+ text-align: center;
19
+ border-top: 2px solid #007cba;
20
+ z-index: 1000;
21
+ }
22
+ .navigation a { margin: 0 10px; padding: 8px 15px; background: #007cba; color: white; text-decoration: none; border-radius: 3px; }
23
+ .navigation a:hover { background: #005a87; }
24
+ .original-image { margin: 20px 0; padding: 20px; background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
25
+ .original-image h3 { margin: 0 0 10px 0; color: #333; }
26
+ .original-image img { max-width: 100%; height: auto; border: 1px solid #ddd; }
27
+ </style>
28
+ </head>
29
+ <body>
30
+ <div class="banner" id="header">
31
+ <script>
32
+ function insert_svg_header(container) {
33
+ const svg_text = ` <svg xmlns='http://www.w3.org/2000/svg'
34
+ width='100%' height='100'
35
+ viewBox='0 0 800 100'
36
+ preserveAspectRatio='xMidYMid meet'>
37
+ <defs>
38
+ <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
39
+ <stop offset="0%" style="stop-color:#0000ff;stop-opacity:1" />
40
+ <stop offset="100%" style="stop-color:#000033;stop-opacity:1" />
41
+ </linearGradient>
42
+ </defs>
43
+ <rect x='0' y='0' width='100%' height='100%' fill='url(#grad1)' />
44
+
45
+ <text x='5%'
46
+ y='52%'
47
+ text-anchor='start'
48
+ style='font-family: Verdana; font-size: 48.0px; font-weight: normal; font-style: normal'
49
+ fill='#fff'>Another gradient test</text>
50
+
51
+ <text x='5%'
52
+ y='82%'
53
+ text-anchor='start'
54
+ style='font-family: Verdana; font-size: 24.0px; font-weight: normal; font-style: normal'
55
+ fill='#fff'>Just one more, I swear</text>
56
+
57
+ </svg>`;
58
+ const svgElement = document.createElement('div');
59
+ svgElement.innerHTML = svg_text;
60
+ const svg = svgElement.firstElementChild;
61
+
62
+ const svgWidth = window.innerWidth;
63
+ const aspectRatio = 8.0;
64
+ const svgHeight = svgWidth / aspectRatio;
65
+
66
+ svg.setAttribute('viewBox', `0 0 ${svgWidth} ${svgHeight}`);
67
+ svg.setAttribute('width', svgWidth);
68
+ svg.setAttribute('height', svgHeight);
69
+
70
+ const titleFontSize = 0.8 * 60;
71
+ const subtitleFontSize = 0.4 * 60;
72
+
73
+ const te1 = svg.querySelector('text:nth-of-type(1)')
74
+ const te2 = svg.querySelector('text:nth-of-type(2)')
75
+
76
+ // Don't override the styles - they're already set correctly in the SVG
77
+ // Just update the positioning and text-anchor
78
+
79
+ const titleXpct = "5%";
80
+ const titleYpct = "52%";
81
+ const subtitleXpct = "5%";
82
+ const subtitleYpct = "82%";
83
+
84
+ const tX = svgWidth * (parseFloat(titleXpct) / 100);
85
+ const tY = svgHeight * (parseFloat(titleYpct) / 100);
86
+ const sX = svgWidth * (parseFloat(subtitleXpct) / 100);
87
+ const sY = svgHeight * (parseFloat(subtitleYpct) / 100);
88
+
89
+ te1.setAttribute('x', tX);
90
+ te1.setAttribute('y', tY);
91
+ te2.setAttribute('x', sX);
92
+ te2.setAttribute('y', sY);
93
+
94
+ // Set text-anchor for proper positioning (use individual anchors if set)
95
+ te1.setAttribute('text-anchor', 'start');
96
+ te2.setAttribute('text-anchor', 'start');
97
+
98
+ // Apply calculated font sizes
99
+ te1.setAttribute('font-size', titleFontSize + 'px');
100
+ te2.setAttribute('font-size', subtitleFontSize + 'px');
101
+
102
+ const containerElement = document.getElementById(container);
103
+ if (containerElement) {
104
+ console.log('Container found, inserting SVG...');
105
+ containerElement.innerHTML = svg.outerHTML;
106
+ console.log('SVG inserted successfully');
107
+ } else {
108
+ console.error('Container not found:', container);
109
+ }
110
+ }
111
+
112
+ console.log('SVG script loaded');
113
+
114
+ // Use DOMContentLoaded to avoid conflicts with main window.onload
115
+ document.addEventListener('DOMContentLoaded', function() {
116
+ console.log('DOM ready, trying SVG insertion...');
117
+ insert_svg_header('header');
118
+ });
119
+ </script>
120
+
121
+ </div>
122
+ <div class="content">
123
+ <div class="description">Linear Gradient (Left to Right)</div>
124
+ <div class="config">back.linear #0000ff #000033 lr
125
+ title.color #fff
126
+ subtitle.color #fff</div>
127
+
128
+ <div class="navigation"><a href="index.html">Back to Index</a> <a href="test24.html">Previous</a></div>
129
+ </div>
130
+ </body>
131
+ </html>
@@ -0,0 +1,205 @@
1
+ # Set up environment for banner tests
2
+ ENV['PATH'] = "#{ENV['HOME']}/.rbenv/shims:#{ENV['PATH']}"
3
+
4
+ # Minimal environment for banner tests
5
+ require 'fileutils'
6
+ require 'find'
7
+
8
+ # Create test directory if it doesn't exist
9
+ test_dir = File.dirname(__FILE__)/"banner-tests"
10
+ FileUtils.rm_rf(test_dir) if Dir.exist?(test_dir)
11
+ Dir.mkdir(test_dir)
12
+
13
+ @pid = nil
14
+ # Start server from the project root directory
15
+ server_dir = File.expand_path("../..", __FILE__)
16
+ Dir.chdir("test") do
17
+ Process.spawn ("ruby -run -e httpd . -p 8000 >/dev/null 2>&1")
18
+ sleep 1
19
+ end
20
+
21
+ def instruct(msg)
22
+ lines = msg.split("\n")
23
+ longest = lines.map {|line| line.length }.max
24
+ puts " +" + "-" * (longest + 4) + "+"
25
+ lines.each do |line|
26
+ puts " | #{line.ljust(longest + 2)} |"
27
+ end
28
+ puts " +" + "-" * (longest + 4) + "+"
29
+ puts
30
+ end
31
+
32
+ def examine(view_name)
33
+ index_url = "http://127.0.0.1:8000/manual/banner-tests/index.html"
34
+
35
+ if ARGV.include?('--automated')
36
+ # Basic validation for automated mode
37
+ index_file = File.dirname(__FILE__)/"banner-tests/index.html"
38
+ if File.exist?(index_file)
39
+ content = File.read(index_file)
40
+ test_count = content.scan(/<div class='test-item'>/).count
41
+
42
+ # Check that at least one test file has custom content
43
+ test_file = File.dirname(__FILE__)/"banner-tests/test04.html" # Red to Blue gradient test
44
+ if File.exist?(test_file)
45
+ test_content = File.read(test_file)
46
+ unless test_content.include?('linearGradient') || test_content.include?('radialGradient') || test_content.include?('fill=\'#ff0000\'')
47
+ puts "⚠ Warning: No custom banner content found"
48
+ end
49
+ end
50
+ else
51
+ puts "✗ Error: Index file not generated"
52
+ exit 1
53
+ end
54
+
55
+ return
56
+ end
57
+
58
+ puts "Press Enter to open the generated front page to inspect the result."
59
+ STDIN.gets
60
+ system("open #{index_url}")
61
+
62
+ puts "Press Enter to kill webrick"
63
+ STDIN.gets
64
+ line = `ps | grep "ruby -run -e httpd" | grep -v grep`
65
+ pid = line.split.first
66
+ pid2 = pid.to_i + 1
67
+ system("kill #{pid} #{pid2}")
68
+ end
69
+
70
+ # Simple post creation for banner tests
71
+ def create_banner_post(title, subtitle, config_content, description, view_name, post_num = nil)
72
+ # Write config file FIRST, before creating banner
73
+ File.write("banner-tests/config.txt", config_content)
74
+
75
+ # Create banner AFTER config is written, in the correct directory
76
+ # Load the main Scriptorium library
77
+ require_relative '../../lib/scriptorium'
78
+
79
+ # Change to the test directory so the banner can find config.txt
80
+ Dir.chdir("banner-tests") do
81
+ banner = Scriptorium::BannerSVG.new(title, subtitle)
82
+
83
+ # Parse config first to set instance variables
84
+ banner.parse_header_svg
85
+
86
+ # Generate static SVG for manual inspection
87
+ # First parse config to set instance variables, then generate SVG
88
+ banner.parse_header_svg
89
+ svg_output = banner.generate_svg
90
+
91
+ # Use provided post_num or generate one
92
+ Dir.mkdir("posts") unless Dir.exist?("posts")
93
+ post_num ||= Dir.glob("posts/*").length + 1
94
+ post_dir = "posts/#{post_num.to_s.rjust(4, '0')}"
95
+ Dir.mkdir(post_dir) unless Dir.exist?(post_dir)
96
+
97
+ # Create individual page with banner at the top
98
+ post_html = <<~HTML
99
+ <!DOCTYPE html>
100
+ <html>
101
+ <head>
102
+ <title>#{title}</title>
103
+ <style>
104
+ body { font-family: Arial, sans-serif; margin: 0; padding: 0; background: #f5f5f5; }
105
+ .banner { width: 100%; margin: 0; padding: 0; }
106
+ .content { padding: 20px; }
107
+ .description { margin: 10px 0; font-weight: bold; }
108
+ .config { background: #f0f0f0; padding: 10px; margin: 10px 0; font-family: monospace; font-size: 12px; }
109
+ .navigation { background: #e0e0e0; padding: 10px; margin: 20px 0; text-align: center; }
110
+ .navigation a { margin: 0 10px; padding: 5px 10px; background: #007cba; color: white; text-decoration: none; border-radius: 3px; }
111
+ .navigation a:hover { background: #005a87; }
112
+ </style>
113
+ </head>
114
+ <body>
115
+ #{svg_output}
116
+ <div class="content">
117
+ <h1>#{title}</h1>
118
+ <div class="description">#{description}</div>
119
+ <div class="config">#{config_content}</div>
120
+ <div class="navigation">
121
+ <a href="../index.html">Back to Index</a>
122
+ </div>
123
+ </div>
124
+ </body>
125
+ </html>
126
+ HTML
127
+
128
+ # Write individual post file
129
+ File.write("#{post_dir}/index.html", post_html)
130
+
131
+ # Add to view for index generation
132
+ view_dir = "views/#{view_name}/output/posts"
133
+ FileUtils.mkdir_p(view_dir) unless Dir.exist?(view_dir)
134
+ File.write("#{view_dir}/#{post_num.to_s.rjust(4, '0')}.html", post_html)
135
+
136
+ # Return post info for navigation links
137
+ { number: post_num, title: title, filename: "#{post_num.to_s.rjust(4, '0')}.html" }
138
+ end
139
+ end
140
+
141
+ def generate_front_page(view_name)
142
+ # Create simple index page
143
+ posts = Dir.glob("scriptorium-TEST/views/#{view_name}/output/posts/*.html").sort
144
+
145
+ index_html = <<~HTML
146
+ <!DOCTYPE html>
147
+ <html>
148
+ <head>
149
+ <title>Banner Tests - #{view_name}</title>
150
+ <style>
151
+ body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
152
+ .post { background: white; margin: 20px 0; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
153
+ .banner { margin: 20px 0; border: 1px solid #ddd; background: white; }
154
+ .description { margin: 10px 0; font-weight: bold; }
155
+ .config { background: #f0f0f0; padding: 10px; margin: 10px 0; font-family: monospace; font-size: 12px; }
156
+ </style>
157
+ </head>
158
+ <body>
159
+ <h1>Banner Tests - #{view_name}</h1>
160
+ HTML
161
+
162
+ posts.each do |post_file|
163
+ post_content = File.read(post_file)
164
+ # Extract title, banner, description, and config from post
165
+ title_match = post_content.match(/<h1>(.*?)<\/h1>/)
166
+ banner_match = post_content.match(/<div class="banner">(.*?)<\/div>/m)
167
+ desc_match = post_content.match(/<div class="description">(.*?)<\/div>/)
168
+ config_match = post_content.match(/<div class="config">(.*?)<\/div>/m)
169
+
170
+ title = title_match ? title_match[1] : "Unknown"
171
+ banner = banner_match ? banner_match[1] : ""
172
+ description = desc_match ? desc_match[1] : ""
173
+ config = config_match ? config_match[1] : ""
174
+
175
+ index_html += <<~HTML
176
+ <div class="post">
177
+ <h2>#{title}</h2>
178
+ <div class="banner">#{banner}</div>
179
+ <div class="description">#{description}</div>
180
+ <div class="config">#{config}</div>
181
+ </div>
182
+ HTML
183
+ end
184
+
185
+ index_html += <<~HTML
186
+ </body>
187
+ </html>
188
+ HTML
189
+
190
+ FileUtils.mkdir_p("scriptorium-TEST/views/#{view_name}/output")
191
+ File.write("scriptorium-TEST/views/#{view_name}/output/index.html", index_html)
192
+ end
193
+
194
+ # Cleanup method to remove standalone directories
195
+ def cleanup_standalone_directories
196
+ if Dir.exist?("posts")
197
+ FileUtils.rm_rf("posts")
198
+ end
199
+ if Dir.exist?("banner-tests")
200
+ FileUtils.rm_rf("banner-tests")
201
+ end
202
+ end
203
+
204
+ # Ensure cleanup happens when script exits
205
+ at_exit { cleanup_standalone_directories }