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,249 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Widget Management - Scriptorium</title>
5
+ <style>
6
+ body {
7
+ font-family: Arial, sans-serif;
8
+ margin: 0;
9
+ padding: 20px;
10
+ background-color: #f5f5f5;
11
+ }
12
+ .container {
13
+ max-width: 1200px;
14
+ margin: 0 auto;
15
+ background: white;
16
+ border-radius: 8px;
17
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
18
+ overflow: hidden;
19
+ }
20
+ .header {
21
+ background: #007bff;
22
+ color: white;
23
+ padding: 20px;
24
+ }
25
+ .header h1 {
26
+ margin: 0;
27
+ font-size: 24px;
28
+ }
29
+ .content {
30
+ padding: 20px;
31
+ }
32
+ .message {
33
+ padding: 10px;
34
+ border-radius: 4px;
35
+ margin-bottom: 20px;
36
+ }
37
+ .message.success {
38
+ background: #d4edda;
39
+ color: #155724;
40
+ border: 1px solid #c3e6cb;
41
+ }
42
+ .message.error {
43
+ background: #f8d7da;
44
+ color: #721c24;
45
+ border: 1px solid #f5c6cb;
46
+ }
47
+ .section {
48
+ margin-bottom: 30px;
49
+ border: 1px solid #ddd;
50
+ border-radius: 6px;
51
+ overflow: hidden;
52
+ }
53
+ .section-header {
54
+ background: #f8f9fa;
55
+ padding: 15px 20px;
56
+ border-bottom: 1px solid #ddd;
57
+ font-weight: bold;
58
+ font-size: 18px;
59
+ }
60
+ .section-content {
61
+ padding: 20px;
62
+ }
63
+ .btn {
64
+ padding: 8px 16px;
65
+ border: none;
66
+ border-radius: 4px;
67
+ cursor: pointer;
68
+ font-size: 14px;
69
+ margin-right: 10px;
70
+ text-decoration: none;
71
+ display: inline-block;
72
+ }
73
+ .btn-primary {
74
+ background: #007bff;
75
+ color: white;
76
+ }
77
+ .btn-primary:hover {
78
+ background: #0056b3;
79
+ }
80
+ .btn-secondary {
81
+ background: #6c757d;
82
+ color: white;
83
+ }
84
+ .btn-secondary:hover {
85
+ background: #545b62;
86
+ }
87
+ .btn-danger {
88
+ background: #dc3545;
89
+ color: white;
90
+ }
91
+ .btn-danger:hover {
92
+ background: #c82333;
93
+ }
94
+ .btn-sm {
95
+ padding: 4px 8px;
96
+ font-size: 12px;
97
+ }
98
+ .widget-grid {
99
+ display: grid;
100
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
101
+ gap: 20px;
102
+ margin-top: 20px;
103
+ }
104
+ .widget-card {
105
+ border: 1px solid #ddd;
106
+ border-radius: 6px;
107
+ padding: 15px;
108
+ background: white;
109
+ }
110
+ .widget-card.configured {
111
+ border-color: #28a745;
112
+ background-color: #f8fff9;
113
+ }
114
+ .widget-card h4 {
115
+ margin: 0 0 10px 0;
116
+ color: #333;
117
+ }
118
+ .widget-status {
119
+ font-size: 12px;
120
+ margin-bottom: 10px;
121
+ }
122
+ .widget-status.configured {
123
+ color: #28a745;
124
+ }
125
+ .widget-status.available {
126
+ color: #6c757d;
127
+ }
128
+ .add-widget-form {
129
+ background: #f8f9fa;
130
+ padding: 15px;
131
+ border-radius: 6px;
132
+ margin-bottom: 20px;
133
+ }
134
+ .add-widget-form form {
135
+ display: flex;
136
+ gap: 10px;
137
+ align-items: end;
138
+ }
139
+ .add-widget-form select, .add-widget-form input[type="text"] {
140
+ padding: 8px;
141
+ border: 1px solid #ddd;
142
+ border-radius: 4px;
143
+ }
144
+ .back-link {
145
+ margin-bottom: 20px;
146
+ }
147
+ </style>
148
+ </head>
149
+ <body>
150
+ <div class="container">
151
+ <div class="header">
152
+ <h1>Widget Management</h1>
153
+ </div>
154
+
155
+ <div class="content">
156
+ <div class="back-link">
157
+ <a href="/view/<%= @current_view.name %>" class="btn btn-secondary">← Back to View Dashboard</a>
158
+ </div>
159
+
160
+ <% if @error %>
161
+ <div class="message error">
162
+ <strong>Error:</strong> <%= @error %>
163
+ </div>
164
+ <% end %>
165
+
166
+ <% if @message %>
167
+ <div class="message success">
168
+ <strong>Success:</strong> <%= @message %>
169
+ </div>
170
+ <% end %>
171
+
172
+ <div class="section">
173
+ <div class="section-header">
174
+ Add New Widget
175
+ </div>
176
+ <div class="section-content">
177
+ <div class="add-widget-form">
178
+ <form method="post" action="/add_widget">
179
+ <select name="widget_name" required>
180
+ <option value="">Select a widget...</option>
181
+ <% @available_widgets.each do |widget| %>
182
+ <% unless @configured_widgets.include?(widget) %>
183
+ <option value="<%= widget %>"><%= widget.capitalize %></option>
184
+ <% end %>
185
+ <% end %>
186
+ </select>
187
+ <button type="submit" class="btn btn-primary">Add Widget</button>
188
+ </form>
189
+ </div>
190
+ <p><em>Note: Widgets will be added to the first available left or right container in your layout.</em></p>
191
+ </div>
192
+ </div>
193
+
194
+ <div class="section">
195
+ <div class="section-header">
196
+ Widgets for <%= @current_view.name %>
197
+ </div>
198
+ <div class="section-content">
199
+ <% if @configured_widgets.empty? %>
200
+ <p>No widgets configured yet. Use the form above to add your first widget.</p>
201
+ <% else %>
202
+ <div class="widget-grid">
203
+ <% @configured_widgets.each do |widget| %>
204
+ <div class="widget-card configured">
205
+ <h4><%= widget.capitalize %> Widget</h4>
206
+ <div class="widget-status configured">✓ Configured</div>
207
+ <% if @widget_containers[widget] %>
208
+ <div style="font-size: 12px; color: #666; margin-bottom: 10px;">
209
+ Container: <strong><%= @widget_containers[widget] %></strong>
210
+ </div>
211
+ <% end %>
212
+ <div>
213
+ <a href="/config_widget/<%= widget %>" class="btn btn-primary btn-sm">Configure</a>
214
+ <form method="post" action="/remove_widget" style="display: inline;">
215
+ <input type="hidden" name="widget_name" value="<%= widget %>">
216
+ <button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('Are you sure you want to remove this widget?')">Remove</button>
217
+ </form>
218
+ </div>
219
+ </div>
220
+ <% end %>
221
+ </div>
222
+ <% end %>
223
+ </div>
224
+ </div>
225
+
226
+ <div class="section">
227
+ <div class="section-header">
228
+ Available Widgets
229
+ </div>
230
+ <div class="section-content">
231
+ <p>The following widget types are available in Scriptorium:</p>
232
+ <ul>
233
+ <% @available_widgets.each do |widget| %>
234
+ <li>
235
+ <strong><%= widget.capitalize %></strong>
236
+ <% if @configured_widgets.include?(widget) %>
237
+ <span style="color: #28a745;">✓ Already configured</span>
238
+ <% else %>
239
+ <span style="color: #6c757d;">Available to add</span>
240
+ <% end %>
241
+ </li>
242
+ <% end %>
243
+ </ul>
244
+ </div>
245
+ </div>
246
+ </div>
247
+ </div>
248
+ </body>
249
+ </html>
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # rbenv hack to ensure correct Ruby version
4
+ ENV['PATH'] = "#{ENV['HOME']}/.rbenv/shims:#{ENV['PATH']}"
5
+ ENV['RBENV_VERSION'] = '3.2.3'
6
+
7
+ require 'optparse'
8
+ require 'json'
9
+ require 'net/http'
10
+ require 'uri'
11
+ require 'fileutils'
12
+ require_relative '../../../lib/scriptorium'
13
+
14
+
15
+ class ScriptoriumWebServer
16
+ def initialize
17
+ @port = 4567
18
+ @pid_file = __dir__/"../tmp/web_server.pid"
19
+ @log_file = __dir__/"../tmp/web_server.log"
20
+
21
+ # Parse command line arguments for test mode
22
+ @testing = ARGV.include?('--test')
23
+
24
+ # Remove --test from ARGV so it doesn't interfere with other processing
25
+ ARGV.delete('--test')
26
+
27
+ # Web server initialized with test mode: #{@testing}
28
+ end
29
+
30
+ def start
31
+ system("kill -9 $(lsof -ti:4567) 2>/dev/null")
32
+ if running?
33
+ puts "Server is already running on port #{@port}"
34
+ return
35
+ end
36
+
37
+ # Create tmp directory if it doesn't exist
38
+ FileUtils.mkdir_p(File.dirname(@pid_file))
39
+
40
+ # Start the server in background
41
+ cmd = "cd #{__dir__}/.. && ruby app/app.rb"
42
+ if @testing
43
+ cmd += " --test"
44
+ end
45
+
46
+ pid = Process.spawn(cmd,
47
+ out: @log_file,
48
+ err: @log_file,
49
+ pgroup: true)
50
+
51
+ # Save PID
52
+ File.write(@pid_file, pid.to_s)
53
+
54
+ # Wait a moment and check if it started successfully
55
+ sleep 2
56
+ unless running?
57
+ puts "❌ Server failed to start. Check logs: #{@log_file}"
58
+ exit 1
59
+ end
60
+ end
61
+
62
+ def stop
63
+ system("rm #@log_file")
64
+ system("touch #@log_file")
65
+ unless File.exist?(@pid_file)
66
+ return
67
+ end
68
+
69
+ pid = File.read(@pid_file).strip.to_i
70
+
71
+ begin
72
+ Process.kill('TERM', pid)
73
+ Process.wait(pid)
74
+ rescue Errno::ESRCH, Errno::ECHILD
75
+ # Server already stopped
76
+ ensure
77
+ File.delete(@pid_file) if File.exist?(@pid_file)
78
+ end
79
+ system("kill -9 $(lsof -ti:4567) 2>/dev/null")
80
+ end
81
+
82
+ def status
83
+ if running?
84
+ # Try to get JSON status
85
+ begin
86
+ response = Net::HTTP.get_response(URI("http://localhost:#{@port}/status"))
87
+ if response.code == "200"
88
+ status_data = JSON.parse(response.body)
89
+ puts "Current view: #{status_data['current_view'] || 'none'}"
90
+ puts "Repository loaded: #{status_data['repo_loaded']}"
91
+ end
92
+ rescue => e
93
+ puts "Could not fetch status: #{e.message}"
94
+ end
95
+ else
96
+ puts "❌ Server is not running"
97
+ end
98
+ end
99
+
100
+ def logfile
101
+ system("cat #@log_file | more")
102
+ end
103
+
104
+ def restart
105
+ stop
106
+ sleep 1
107
+ start
108
+ end
109
+
110
+ private
111
+
112
+ def running?
113
+ return false unless File.exist?(@pid_file)
114
+
115
+ pid = File.read(@pid_file).strip.to_i
116
+ Process.kill(0, pid)
117
+ true
118
+ rescue Errno::ESRCH, Errno::ENOENT
119
+ false
120
+ end
121
+ end
122
+
123
+ # Parse command line options
124
+ options = {}
125
+ OptionParser.new do |opts|
126
+ opts.banner = "Usage: scriptorium-web [start|stop|restart|status|log]"
127
+
128
+ opts.on("-p", "--port PORT", Integer, "Port number (default: 4567)") do |port|
129
+ options[:port] = port
130
+ end
131
+
132
+ opts.on("--test", "Use test repository (scriptorium-TEST)") do
133
+ options[:test] = true
134
+ end
135
+ end.parse!
136
+
137
+ # Get command
138
+ command = ARGV.first || 'status'
139
+
140
+ # Create server instance
141
+ server = ScriptoriumWebServer.new
142
+ server.instance_variable_set(:@port, options[:port]) if options[:port]
143
+ server.instance_variable_set(:@testing, options[:test]) if options[:test]
144
+
145
+ # Launcher options: #{options.inspect}
146
+ # Server testing mode: #{server.instance_variable_get(:@testing)}
147
+
148
+ # Execute command
149
+ case command
150
+ when 'start'
151
+ server.start
152
+ when 'stop'
153
+ server.stop
154
+ when 'log'
155
+ server.logfile
156
+ when 'restart'
157
+ server.restart
158
+ when 'status'
159
+ server.status
160
+ else
161
+ puts "Unknown command: #{command}"
162
+ puts "Usage: scriptorium-web [start|stop|restart|status]"
163
+ exit 1
164
+ end
@@ -0,0 +1,38 @@
1
+ require 'minitest/autorun'
2
+ require_relative '../../../lib/scriptorium'
3
+
4
+ class WebBasicTest < Minitest::Test
5
+ def test_web_structure
6
+ # Test that the web app file exists
7
+ app_file = File.join(__dir__, '..', 'app', 'app.rb')
8
+ assert File.exist?(app_file), "Web app should exist at #{app_file}"
9
+
10
+ # Test that the dashboard template exists
11
+ template_file = File.join(__dir__, '..', 'app', 'views', 'dashboard.erb')
12
+ assert File.exist?(template_file), "Dashboard template should exist at #{template_file}"
13
+
14
+ # Test that the server management script exists
15
+ server_script = File.join(__dir__, '..', 'bin', 'scriptorium-web')
16
+ assert File.exist?(server_script), "Server script should exist at #{server_script}"
17
+ assert File.executable?(server_script), "Server script should be executable"
18
+ end
19
+
20
+ def test_api_integration
21
+ # Test that the web app can create an API instance
22
+ api = Scriptorium::API.new(testmode: true)
23
+ assert api, "Should be able to create API instance"
24
+
25
+ # Test that we can check for repository
26
+ assert_respond_to api, :views, "API should respond to views method"
27
+ end
28
+
29
+ def test_server_script_requires
30
+ # Test that the server script has the necessary requires
31
+ server_script = File.join(__dir__, '..', 'bin', 'scriptorium-web')
32
+ content = File.read(server_script)
33
+
34
+ assert content.include?('require \'optparse\''), "Should require optparse"
35
+ assert content.include?('require \'json\''), "Should require json"
36
+ assert content.include?('require \'net/http\''), "Should require net/http"
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ =About
2
+ Vision & Mission mission
3
+ Board of Directors board
4
+ -Social Media socmed
5
+ =Resources
6
+ Space links links
7
+ -Blog embed-blog
@@ -0,0 +1,17 @@
1
+ {"ts":"2025-09-19T02:38:50Z","ip":"127.0.0.1","ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36","path":"/debug/timing","data":{"label":"preview_onload","ms":0.3000001907348633,"href":"http://localhost:4567/preview/computing/index.html"}}
2
+ {"ts":"2025-09-19T02:45:50Z","ip":"127.0.0.1","ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36","path":"/debug/timing","data":{"label":"preview_onload","ms":0.2999997138977051,"href":"http://localhost:4567/preview/computing/index.html"}}
3
+ {"ts":"2025-09-19T02:53:09Z","label":"server_generate_view","route":"/preview","view":"computing","ms":2632.339}
4
+ {"ts":"2025-09-19T02:53:12Z","label":"server_generate_view","route":"/preview/:view_name/index.html","view":"computing","ms":2862.597}
5
+ {"ts":"2025-09-19T02:53:13Z","ip":"127.0.0.1","ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36","path":"/debug/timing","data":{"label":"preview_onload","ms":0.2999997138977051,"href":"http://localhost:4567/preview/computing/index.html"}}
6
+ {"ts":"2025-09-19T03:05:59Z","label":"server_generate_view","route":"/preview","view":"computing","ms":2960.1440000000002}
7
+ {"ts":"2025-09-19T03:06:02Z","label":"server_generate_view","route":"/preview/:view_name/index.html","view":"computing","ms":2725.7259999999997}
8
+ {"ts":"2025-09-19T03:06:02Z","ip":"127.0.0.1","ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36","path":"/debug/timing","data":{"label":"preview_onload","ms":0.2999997138977051,"href":"http://localhost:4567/preview/computing/index.html"}}
9
+ {"ts":"2025-09-19T03:09:16Z","label":"server_generate_view","route":"/preview","view":"computing","ms":3297.264}
10
+ {"ts":"2025-09-19T03:09:20Z","label":"server_generate_view","route":"/preview/:view_name/index.html","view":"computing","ms":3389.914}
11
+ {"ts":"2025-09-19T03:09:20Z","ip":"127.0.0.1","ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36","path":"/debug/timing","data":{"label":"preview_onload","ms":0.20000028610229492,"href":"http://localhost:4567/preview/computing/index.html"}}
12
+ {"ts":"2025-09-19T03:09:32Z","label":"server_generate_view","route":"/preview","view":"computing","ms":3087.198}
13
+ {"ts":"2025-09-19T03:09:36Z","label":"server_generate_view","route":"/preview/:view_name/index.html","view":"computing","ms":3658.665}
14
+ {"ts":"2025-09-19T03:09:36Z","ip":"127.0.0.1","ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36","path":"/debug/timing","data":{"label":"preview_onload","ms":0.3000001907348633,"href":"http://localhost:4567/preview/computing/index.html"}}
15
+ {"ts":"2025-09-19T03:15:27Z","label":"server_generate_view","route":"/preview","view":"computing","ms":2712.335}
16
+ {"ts":"2025-09-19T03:15:30Z","label":"server_generate_view","route":"/preview/:view_name/index.html","view":"computing","ms":2674.076}
17
+ {"ts":"2025-09-19T03:15:30Z","ip":"127.0.0.1","ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36","path":"/debug/timing","data":{"label":"preview_onload","ms":0.3000001907348633,"href":"http://localhost:4567/preview/computing/index.html"}}
File without changes