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,229 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'minitest/autorun'
4
+ require_relative '../lib/scriptorium'
5
+ require_relative 'test_helpers'
6
+
7
+ class LivetextPluginTest < Minitest::Test
8
+ include TestHelpers
9
+
10
+ def setup
11
+ @test_repo_path = "scriptorium-TEST"
12
+ cleanup_test_repo
13
+ end
14
+
15
+ def teardown
16
+ cleanup_test_repo
17
+ end
18
+
19
+ def test_001_basic_dot_commands
20
+ # Test basic dot commands that should work
21
+ content = <<~EOS
22
+ .title My Test Post
23
+ .created
24
+ .views sample
25
+ .tags ruby, testing
26
+ .blurb This is a test post
27
+ This is the body content
28
+ EOS
29
+
30
+ result = process_livetext(content)
31
+
32
+ # Check that variables were set correctly
33
+ assert_equal("My Test Post", result[:vars][:"post.title"])
34
+ assert_equal("sample", result[:vars][:"post.views"])
35
+ assert_equal("ruby, testing", result[:vars][:"post.tags"])
36
+ assert_equal("This is a test post", result[:vars][:"post.blurb"])
37
+
38
+ # Check that body text is returned
39
+ assert_match(/This is the body content/, result[:text])
40
+ end
41
+
42
+ # def test_002_html_formatting_commands
43
+ # # Test HTML formatting commands
44
+ # content = <<~EOS
45
+ # .h1 Main Heading
46
+ # .h2 Sub Heading
47
+ # .list
48
+ # Item 1
49
+ # Item 2
50
+ # Item 3
51
+ # .end
52
+ # .nlist
53
+ # Numbered 1
54
+ # Numbered 2
55
+ # .end
56
+ # .quote
57
+ # This is a quote
58
+ # .end
59
+ # .hr
60
+ # EOS
61
+ #
62
+ # result = process_livetext(content)
63
+ #
64
+ # # Check HTML output
65
+ # assert_match(/<h1>Main Heading<\/h1>/, result[:text])
66
+ # assert_match(/<h2>Sub Heading<\/h2>/, result[:text])
67
+ # assert_match(/<ul>/, result[:text])
68
+ # assert_match(/<li>Item 1<\/li>/, result[:text])
69
+ # assert_match(/<ol>/, result[:text])
70
+ # assert_match(/<li>Numbered 1<\/li>/, result[:text])
71
+ # assert_match(/<blockquote>/, result[:text])
72
+ # assert_match(/<hr>/, result[:text])
73
+ # end
74
+
75
+ # def test_003_special_formatting
76
+ # # Test special formatting like dropcap and inset
77
+ # content = <<~EOS
78
+ # .dropcap This is a dropcap test
79
+ # .inset left 25
80
+ # |This goes in the inset
81
+ # This goes in the body
82
+ # /This only goes in inset
83
+ # .end
84
+ # EOS
85
+ #
86
+ # result = process_livetext(content)
87
+ #
88
+ # # Check for dropcap formatting
89
+ # assert_match(/mydrop/, result[:text])
90
+ # assert_match(/his is a dropcap test/, result[:text]) # The remainder after the dropcap
91
+ #
92
+ # # Check for inset formatting
93
+ # assert_match(/float:left/, result[:text])
94
+ # assert_match(/width: 25%/, result[:text])
95
+ # end
96
+
97
+ # def test_004_functions
98
+ # # Test Livetext functions
99
+ # content = <<~EOS
100
+ # $$br:2
101
+ # $$h1[Function Heading]
102
+ # $$h2[Sub Heading]
103
+ # $$image:test.jpg
104
+ # EOS
105
+ #
106
+ # result = process_livetext(content)
107
+ #
108
+ # # Check function output
109
+ # assert_match(/<br><br>/, result[:text])
110
+ # assert_match(/<h1>Function Heading<\/h1>/, result[:text])
111
+ # assert_match(/<h2>Sub Heading<\/h2>/, result[:text])
112
+ # assert_match(/<img src='test\.jpg'><\/img>/, result[:text])
113
+ # end
114
+
115
+ # def test_005_faq_command
116
+ # # Test the FAQ command
117
+ # content = <<~EOS
118
+ # .faq What is this?
119
+ # This is a test question and answer.
120
+ # .end
121
+ # .faq Another question?
122
+ # Another answer.
123
+ # .end
124
+ # EOS
125
+ #
126
+ # result = process_livetext(content)
127
+ #
128
+ # # Check FAQ formatting
129
+ # assert_match(/data-toggle="collapse"/, result[:text])
130
+ # assert_match(/What is this\?/, result[:text])
131
+ # assert_match(/This is a test question and answer/, result[:text])
132
+ # assert_match(/Another question\?/, result[:text])
133
+ # end
134
+
135
+ # def test_006_last_updated_command
136
+ # # Test the last_updated command
137
+ # content = <<~EOS
138
+ # .created
139
+ # .title Test Post
140
+ # .last_updated
141
+ # EOS
142
+ #
143
+ # result = process_livetext(content)
144
+ #
145
+ # # Check that last_updated outputs the publication date
146
+ # assert_match(/Published:/, result[:text])
147
+ # today = Time.now.strftime("%Y-%m-%d")
148
+ # assert_match(/#{today}/, result[:text]) # Should match today's date
149
+ # end
150
+
151
+ # def test_007_wordcount_function
152
+ # # Test the wordcount function
153
+ # content = <<~EOS
154
+ # .title Test Post
155
+ # This is a test post with some words.
156
+ # It has multiple sentences and paragraphs.
157
+ #
158
+ # .wordcount
159
+ # The file $File has $wordcount words.
160
+ #
161
+ # More content here to increase the word count.
162
+ # This should be counted as well.
163
+ # EOS
164
+ #
165
+ # result = process_livetext(content)
166
+ #
167
+ # # Check that wordcount function worked
168
+ # assert_match(/The file .* has \d+ words\./, result[:text])
169
+ # # Should not contain the literal ".wordcount" if working
170
+ # refute_match(/\.wordcount/, result[:text])
171
+ # # Should not contain the literal "$wordcount" if working
172
+ # refute_match(/\$wordcount/, result[:text])
173
+ # end
174
+
175
+ # def test_008_stats_command
176
+ # # Test the stats command that sets multiple variables
177
+ # content = <<~EOS
178
+ # .title Test Post
179
+ # This is a test post with some words.
180
+ # It has multiple sentences and paragraphs.
181
+ #
182
+ # .stats
183
+ # This file has $file.wordcount words, $file.charcount characters, and takes about $file.readingtime minutes to read.
184
+ #
185
+ # More content here to increase the word count.
186
+ # This should be counted as well.
187
+ # EOS
188
+ #
189
+ # result = process_livetext(content)
190
+ #
191
+ # # Check that stats command worked
192
+ # assert_match(/This file has \d+ words, \d+ characters, and takes about \d+ minutes to read\./, result[:text])
193
+ # # Should not contain the literal ".stats" if working
194
+ # refute_match(/\.stats/, result[:text])
195
+ # # Should not contain the literal variable names if working
196
+ # refute_match(/\$file\.wordcount/, result[:text])
197
+ # refute_match(/\$file\.charcount/, result[:text])
198
+ # refute_match(/\$file\.readingtime/, result[:text])
199
+ # end
200
+
201
+ private
202
+
203
+ def process_livetext(content)
204
+ # Create a temporary file with the content
205
+ temp_file = "test/temp_livetext.lt3"
206
+ write_file(temp_file, content)
207
+
208
+ # Process with Livetext using the plugin
209
+ begin
210
+ # Use the new unified Livetext API
211
+ live = Livetext.customize(mix: "lt3scriptor", call: ".nopara")
212
+ body, vars = live.process(file: temp_file)
213
+
214
+ # Return the actual data structures
215
+ return { vars: vars, text: body, body: body }
216
+ rescue => e
217
+ return { error: e.message, backtrace: e.backtrace.first }
218
+ ensure
219
+ # Clean up
220
+ File.delete(temp_file) if File.exist?(temp_file)
221
+ end
222
+ end
223
+
224
+ def cleanup_test_repo
225
+ if Dir.exist?(@test_repo_path)
226
+ FileUtils.rm_rf(@test_repo_path)
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Manual test for asset management functionality
4
+ # This is a MANUAL test - you need to run it step by step
5
+
6
+ require_relative "../../lib/scriptorium"
7
+ require_relative "../test_helpers"
8
+ require "fileutils"
9
+ require_relative "./environment"
10
+
11
+ manual_setup
12
+
13
+ @repo.create_view("assetview", "Asset Test View", "A test view for asset management")
14
+
15
+ # Copy test images from dev_assets
16
+ FileUtils.cp("dev_assets/global.png", "test/scriptorium-TEST/assets/global-test.png")
17
+ FileUtils.cp("dev_assets/view.png", "test/scriptorium-TEST/views/assetview/assets/view-test.png")
18
+ FileUtils.mkdir_p("test/scriptorium-TEST/posts/0001/assets")
19
+ FileUtils.cp("dev_assets/post.png", "test/scriptorium-TEST/posts/0001/assets/post-test.png")
20
+ FileUtils.mkdir_p("test/scriptorium-TEST/assets/library")
21
+ FileUtils.cp("dev_assets/library.png", "test/scriptorium-TEST/assets/library/library-test.png")
22
+
23
+ # Create a post with asset references
24
+ draft_body = <<~BODY
25
+ .blurb Testing asset management with real images.
26
+
27
+ This post tests the asset management system with real PNG files.
28
+
29
+ Global asset: $$asset[global-test.png]
30
+
31
+ View asset: $$asset[view-test.png]
32
+
33
+ Post asset: $$asset[post-test.png]
34
+
35
+ Library asset: $$asset[library-test.png]
36
+
37
+ Missing asset: $$asset[nonexistent.png]
38
+
39
+ And with image tags:
40
+
41
+ $$image_asset[global-test.png]
42
+ $$image_asset[view-test.png]
43
+ $$image_asset[post-test.png]
44
+ $$image_asset[library-test.png]
45
+ $$image_asset[nonexistent.png]
46
+
47
+ The assets should be copied to the output directory and display correctly.
48
+ BODY
49
+
50
+ name = @repo.create_draft(title: "Asset Management Test", views: ["assetview"], body: draft_body)
51
+ num = @repo.finish_draft(name)
52
+ @repo.generate_post(num)
53
+
54
+ @repo.generate_front_page("assetview")
55
+
56
+ instruct <<~EOS
57
+ The post should display with:
58
+ - Global image (global-test.png) from assets/
59
+ - View image (view-test.png) from views/assetview/assets/
60
+ - Post image (post-test.png) from posts/0001/assets/
61
+ - Library image (library-test.png) from assets/library/
62
+ - Missing image placeholder for nonexistent.png
63
+
64
+ Check that images are copied to views/assetview/output/assets/
65
+ and that URLs are generated correctly.
66
+ EOS
67
+ examine("assetview")
@@ -0,0 +1,3 @@
1
+ back.linear #0000ff #000033 lr
2
+ title.color #fff
3
+ subtitle.color #fff
@@ -0,0 +1,45 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>BannerSVG Feature Tests</title>
5
+ <style>
6
+ body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
7
+ .test-list { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
8
+ .test-item { margin: 10px 0; padding: 10px; background: #f9f9f9; border-left: 4px solid #007cba; }
9
+ .test-item a { color: #007cba; text-decoration: none; font-weight: bold; }
10
+ .test-item a:hover { text-decoration: underline; }
11
+ .test-description { color: #666; font-size: 14px; margin-top: 5px; }
12
+ </style>
13
+ </head>
14
+ <body>
15
+ <h1>BannerSVG Feature Tests</h1>
16
+ <div class="test-list">
17
+ <p>Click on any test to view the banner in isolation:</p>
18
+ <div class='test-item'><a href='test01.html'>1. Red Background</a><div class='test-description'>Red Background</div></div>
19
+ <div class='test-item'><a href='test02.html'>2. Blue Background</a><div class='test-description'>Blue Background</div></div>
20
+ <div class='test-item'><a href='test03.html'>3. Green Background</a><div class='test-description'>Green Background</div></div>
21
+ <div class='test-item'><a href='test04.html'>4. Red to Blue Gradient</a><div class='test-description'>Linear Gradient (Left to Right)</div></div>
22
+ <div class='test-item'><a href='test05.html'>5. Green to Yellow Gradient</a><div class='test-description'>Linear Gradient (Top to Bottom)</div></div>
23
+ <div class='test-item'><a href='test06.html'>6. Red to Blue Radial</a><div class='test-description'>Radial Gradient</div></div>
24
+ <div class='test-item'><a href='test07.html'>7. Green to Yellow Radial</a><div class='test-description'>Radial Gradient</div></div>
25
+ <div class='test-item'><a href='test08.html'>8. Small Text</a><div class='test-description'>Small Text (0.5x, 0.3x)</div></div>
26
+ <div class='test-item'><a href='test09.html'>9. Large Text</a><div class='test-description'>Large Text (1.5x, 1.0x)</div></div>
27
+ <div class='test-item'><a href='test10.html'>10. Bold Text</a><div class='test-description'>Bold Text</div></div>
28
+ <div class='test-item'><a href='test11.html'>11. Italic Text</a><div class='test-description'>Italic Text</div></div>
29
+ <div class='test-item'><a href='test12.html'>12. Bold & Italic</a><div class='test-description'>Bold & Italic Text</div></div>
30
+ <div class='test-item'><a href='test13.html'>13. Blue Text</a><div class='test-description'>Blue Text</div></div>
31
+ <div class='test-item'><a href='test14.html'>14. Green Text</a><div class='test-description'>Green Text</div></div>
32
+ <div class='test-item'><a href='test15.html'>15. Left Position</a><div class='test-description'>Left Positioned Text</div></div>
33
+ <div class='test-item'><a href='test16.html'>16. Center Position</a><div class='test-description'>Center Positioned Text</div></div>
34
+ <div class='test-item'><a href='test17.html'>17. Right Position</a><div class='test-description'>Right Positioned Text</div></div>
35
+ <div class='test-item'><a href='test18.html'>18. Perfect Image Background</a><div class='test-description'>Perfect match: 8:1 aspect ratio image fits banner exactly - no cropping or scaling needed</div></div>
36
+ <div class='test-item'><a href='test19.html'>19. Wide Image Background</a><div class='test-description'>Wide image (16:1) cropped to fit 8:1 banner - left/right edges removed, center preserved</div></div>
37
+ <div class='test-item'><a href='test20.html'>20. Tall Image Background</a><div class='test-description'>Square image (1:1) cropped to fit 8:1 banner - top/bottom removed, center strip visible</div></div>
38
+ <div class='test-item'><a href='test21.html'>21. Very Tall Image Background</a><div class='test-description'>Very tall image (1:4) heavily cropped - only narrow center strip visible, most content lost</div></div>
39
+ <div class='test-item'><a href='test22.html'>22. Very Wide Image Background</a><div class='test-description'>Very wide image (16:1) heavily cropped - only narrow center strip visible, sides removed</div></div>
40
+ <div class='test-item'><a href='test23.html'>23. Small Image Background</a><div class='test-description'>Small low-res image scaled up to fill banner - may appear pixelated but maintains aspect</div></div>
41
+ <div class='test-item'><a href='test24.html'>24. Odd Aspect Image Background</a><div class='test-description'>Non-standard aspect ratio (~4:1) cropped to fit 8:1 banner - moderate cropping applied</div></div>
42
+ <div class='test-item'><a href='test25.html'>25. Another gradient test</a><div class='test-description'>Linear Gradient (Left to Right)</div></div>
43
+ </div>
44
+ </body>
45
+ </html>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Red Background</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">
31
+ <svg xmlns='http://www.w3.org/2000/svg'
32
+ width='100%' height='100'
33
+ viewBox='0 0 800 100'
34
+ preserveAspectRatio='xMidYMid meet'>
35
+ <rect x='0' y='0' width='100%' height='100%' fill='#ff0000' />
36
+ <text x='5%'
37
+ y='52%'
38
+ text-anchor='start'
39
+ style='font-family: Verdana; font-size: 48px; font-weight: normal; font-style: normal'
40
+ fill='#374151'>Red Background</text>
41
+
42
+ <text x='5%'
43
+ y='82%'
44
+ text-anchor='start'
45
+ style='font-family: Verdana; font-size: 24px; font-weight: normal; font-style: normal'
46
+ fill='#374151'>Solid color test</text>
47
+
48
+ </svg>
49
+
50
+ </div>
51
+ <div class="content">
52
+ <div class="description">Red Background</div>
53
+ <div class="config">back.color #ff0000</div>
54
+
55
+ <div class="navigation"><a href="index.html">Back to Index</a> <a href="test02.html">Next</a></div>
56
+ </div>
57
+ </body>
58
+ </html>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Blue Background</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">
31
+ <svg xmlns='http://www.w3.org/2000/svg'
32
+ width='100%' height='100'
33
+ viewBox='0 0 800 100'
34
+ preserveAspectRatio='xMidYMid meet'>
35
+ <rect x='0' y='0' width='100%' height='100%' fill='#0000ff' />
36
+ <text x='5%'
37
+ y='52%'
38
+ text-anchor='start'
39
+ style='font-family: Verdana; font-size: 48px; font-weight: normal; font-style: normal'
40
+ fill='#374151'>Blue Background</text>
41
+
42
+ <text x='5%'
43
+ y='82%'
44
+ text-anchor='start'
45
+ style='font-family: Verdana; font-size: 24px; font-weight: normal; font-style: normal'
46
+ fill='#374151'>Solid color test</text>
47
+
48
+ </svg>
49
+
50
+ </div>
51
+ <div class="content">
52
+ <div class="description">Blue Background</div>
53
+ <div class="config">back.color #0000ff</div>
54
+
55
+ <div class="navigation"><a href="index.html">Back to Index</a> <a href="test01.html">Previous</a> <a href="test03.html">Next</a></div>
56
+ </div>
57
+ </body>
58
+ </html>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Green Background</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">
31
+ <svg xmlns='http://www.w3.org/2000/svg'
32
+ width='100%' height='100'
33
+ viewBox='0 0 800 100'
34
+ preserveAspectRatio='xMidYMid meet'>
35
+ <rect x='0' y='0' width='100%' height='100%' fill='#00ff00' />
36
+ <text x='5%'
37
+ y='52%'
38
+ text-anchor='start'
39
+ style='font-family: Verdana; font-size: 48px; font-weight: normal; font-style: normal'
40
+ fill='#374151'>Green Background</text>
41
+
42
+ <text x='5%'
43
+ y='82%'
44
+ text-anchor='start'
45
+ style='font-family: Verdana; font-size: 24px; font-weight: normal; font-style: normal'
46
+ fill='#374151'>Solid color test</text>
47
+
48
+ </svg>
49
+
50
+ </div>
51
+ <div class="content">
52
+ <div class="description">Green Background</div>
53
+ <div class="config">back.color #00ff00</div>
54
+
55
+ <div class="navigation"><a href="index.html">Back to Index</a> <a href="test02.html">Previous</a> <a href="test04.html">Next</a></div>
56
+ </div>
57
+ </body>
58
+ </html>
@@ -0,0 +1,65 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Red to Blue Gradient</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">
31
+ <svg xmlns='http://www.w3.org/2000/svg'
32
+ width='100%' height='100'
33
+ viewBox='0 0 800 100'
34
+ preserveAspectRatio='xMidYMid meet'>
35
+ <defs>
36
+ <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
37
+ <stop offset="0%" style="stop-color:red;stop-opacity:1" />
38
+ <stop offset="100%" style="stop-color:blue;stop-opacity:1" />
39
+ </linearGradient>
40
+ </defs>
41
+ <rect x='0' y='0' width='100%' height='100%' fill='url(#grad1)' />
42
+
43
+ <text x='5%'
44
+ y='52%'
45
+ text-anchor='start'
46
+ style='font-family: Verdana; font-size: 48px; font-weight: normal; font-style: normal'
47
+ fill='#374151'>Red to Blue Gradient</text>
48
+
49
+ <text x='5%'
50
+ y='82%'
51
+ text-anchor='start'
52
+ style='font-family: Verdana; font-size: 24px; font-weight: normal; font-style: normal'
53
+ fill='#374151'>Linear gradient test</text>
54
+
55
+ </svg>
56
+
57
+ </div>
58
+ <div class="content">
59
+ <div class="description">Linear Gradient (Left to Right)</div>
60
+ <div class="config">back.linear red blue lr</div>
61
+
62
+ <div class="navigation"><a href="index.html">Back to Index</a> <a href="test03.html">Previous</a> <a href="test05.html">Next</a></div>
63
+ </div>
64
+ </body>
65
+ </html>
@@ -0,0 +1,65 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Green to Yellow Gradient</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">
31
+ <svg xmlns='http://www.w3.org/2000/svg'
32
+ width='100%' height='100'
33
+ viewBox='0 0 800 100'
34
+ preserveAspectRatio='xMidYMid meet'>
35
+ <defs>
36
+ <linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
37
+ <stop offset="0%" style="stop-color:green;stop-opacity:1" />
38
+ <stop offset="100%" style="stop-color:yellow;stop-opacity:1" />
39
+ </linearGradient>
40
+ </defs>
41
+ <rect x='0' y='0' width='100%' height='100%' fill='url(#grad1)' />
42
+
43
+ <text x='5%'
44
+ y='52%'
45
+ text-anchor='start'
46
+ style='font-family: Verdana; font-size: 48px; font-weight: normal; font-style: normal'
47
+ fill='#374151'>Green to Yellow Gradient</text>
48
+
49
+ <text x='5%'
50
+ y='82%'
51
+ text-anchor='start'
52
+ style='font-family: Verdana; font-size: 24px; font-weight: normal; font-style: normal'
53
+ fill='#374151'>Linear gradient test</text>
54
+
55
+ </svg>
56
+
57
+ </div>
58
+ <div class="content">
59
+ <div class="description">Linear Gradient (Top to Bottom)</div>
60
+ <div class="config">back.linear green yellow tb</div>
61
+
62
+ <div class="navigation"><a href="index.html">Back to Index</a> <a href="test04.html">Previous</a> <a href="test06.html">Next</a></div>
63
+ </div>
64
+ </body>
65
+ </html>