scriptorium 0.6.1 → 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.
- checksums.yaml +4 -4
- data/assets/icons/social/reddit.png +0 -0
- data/assets/icons/social/x-logo.png +0 -0
- data/assets/imagenotfound.jpg +0 -0
- data/bin/sblog +84 -5
- data/bin/scriptorium +1 -0
- data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +0 -1
- data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +0 -29
- data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +0 -19
- data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +1 -1
- data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +1 -1
- data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +1 -1
- data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +0 -10
- data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +1 -4
- data/doc/anti-amnesia/20250901-211714-codemirror-integration-and-web-tests.md +172 -0
- data/doc/anti-amnesia/20250902-002402-backup-restore-system.md +126 -0
- data/doc/anti-amnesia/20250907-203339-backup-metadata-implementation.md +66 -0
- data/doc/imported/0001-elixir-conf-2014/metadata.txt +7 -0
- data/doc/imported/0001-elixir-conf-2014/post.html +37 -0
- data/doc/imported/0001-elixir-conf-2014/source.lt3 +22 -0
- data/doc/imported/0002-programmers-and-word-processing/metadata.txt +7 -0
- data/doc/imported/0002-programmers-and-word-processing/post.html +192 -0
- data/doc/imported/0002-programmers-and-word-processing/source.lt3 +146 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/metadata.txt +7 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/post.html +60 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/source.lt3 +40 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/metadata.txt +7 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/post.html +42 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/source.lt3 +24 -0
- data/doc/imported/0005-elixir-conf-2015-announced/metadata.txt +7 -0
- data/doc/imported/0005-elixir-conf-2015-announced/post.html +30 -0
- data/doc/imported/0005-elixir-conf-2015-announced/source.lt3 +16 -0
- data/doc/imported/0006-ruby-for-dinosaurs/metadata.txt +7 -0
- data/doc/imported/0006-ruby-for-dinosaurs/post.html +43 -0
- data/doc/imported/0006-ruby-for-dinosaurs/source.lt3 +27 -0
- data/doc/imported/0007-phoenix-isnt-rails/metadata.txt +7 -0
- data/doc/imported/0007-phoenix-isnt-rails/post.html +116 -0
- data/doc/imported/0007-phoenix-isnt-rails/source.lt3 +87 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/metadata.txt +7 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/post.html +129 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/source.lt3 +92 -0
- data/doc/imported/0009-announcement-coming-soon/metadata.txt +7 -0
- data/doc/imported/0009-announcement-coming-soon/post.html +33 -0
- data/doc/imported/0009-announcement-coming-soon/source.lt3 +19 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/metadata.txt +7 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/post.html +175 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/source.lt3 +139 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/metadata.txt +7 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/post.html +139 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/source.lt3 +104 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/metadata.txt +7 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/post.html +42 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/source.lt3 +24 -0
- data/doc/imported/0013-rubyday-was-a-success/metadata.txt +7 -0
- data/doc/imported/0013-rubyday-was-a-success/post.html +44 -0
- data/doc/imported/0013-rubyday-was-a-success/source.lt3 +27 -0
- data/doc/imported/0014-working-on-the-blogging-software/metadata.txt +7 -0
- data/doc/imported/0014-working-on-the-blogging-software/post.html +63 -0
- data/doc/imported/0014-working-on-the-blogging-software/source.lt3 +41 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/metadata.txt +7 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/post.html +172 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/source.lt3 +134 -0
- data/doc/imported/0016-an-in-operator-for-ruby/metadata.txt +7 -0
- data/doc/imported/0016-an-in-operator-for-ruby/post.html +155 -0
- data/doc/imported/0016-an-in-operator-for-ruby/source.lt3 +106 -0
- data/doc/imported/0017-the-forgotten-mathematician/metadata.txt +7 -0
- data/doc/imported/0017-the-forgotten-mathematician/post.html +161 -0
- data/doc/imported/0017-the-forgotten-mathematician/source.lt3 +119 -0
- data/doc/imported/0018-ruby-puns/metadata.txt +7 -0
- data/doc/imported/0018-ruby-puns/post.html +46 -0
- data/doc/imported/0018-ruby-puns/source.lt3 +28 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/metadata.txt +7 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/post.html +138 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/source.lt3 +101 -0
- data/doc/imported/0020-fffff/metadata.txt +7 -0
- data/doc/imported/0020-fffff/post.html +24 -0
- data/doc/imported/0020-fffff/source.lt3 +12 -0
- data/doc/imported/0021-trying-ror-yet-again/metadata.txt +7 -0
- data/doc/imported/0021-trying-ror-yet-again/post.html +26 -0
- data/doc/imported/0021-trying-ror-yet-again/source.lt3 +12 -0
- data/doc/imported/0023-doctor-sleep/metadata.txt +7 -0
- data/doc/imported/0023-doctor-sleep/post.html +63 -0
- data/doc/imported/0023-doctor-sleep/source.lt3 +44 -0
- data/doc/imported/0024-just-a-test/metadata.txt +7 -0
- data/doc/imported/0024-just-a-test/post.html +24 -0
- data/doc/imported/0024-just-a-test/source.lt3 +12 -0
- data/doc/imported/import_summary.txt +98 -0
- data/doc/livetext-informal-spec.txt +65 -0
- data/doc/myuserdoc/ch-0.lt3 +31 -0
- data/doc/myuserdoc/ch-1.lt3 +37 -0
- data/doc/myuserdoc/ch-10.lt3 +22 -0
- data/doc/myuserdoc/ch-2.lt3 +37 -0
- data/doc/myuserdoc/ch-3.lt3 +19 -0
- data/doc/myuserdoc/ch-4.lt3 +43 -0
- data/doc/myuserdoc/ch-5.lt3 +22 -0
- data/doc/myuserdoc/ch-6.lt3 +19 -0
- data/doc/myuserdoc/ch-7.lt3 +16 -0
- data/doc/myuserdoc/ch-8.lt3 +13 -0
- data/doc/myuserdoc/ch-9.lt3 +19 -0
- data/doc/myuserdoc/tweak.rb +18 -0
- data/doc/{userdoc-toc.txt → myuserdoc/userdoc-toc.txt} +27 -27
- data/doc/old-posts/0001-elixir-conf-2014.lt3 +24 -0
- data/doc/old-posts/0002-programmers-and-word-processing.lt3 +150 -0
- data/doc/old-posts/0003-how-to-turn-your-brain-sideways.lt3 +43 -0
- data/doc/old-posts/0004-upcoming-lone-star-ruby-conference.lt3 +26 -0
- data/doc/old-posts/0005-elixir-conf-2015-announced.lt3 +17 -0
- data/doc/old-posts/0006-ruby-for-dinosaurs.lt3 +30 -0
- data/doc/old-posts/0007-phoenix-isnt-rails.lt3 +90 -0
- data/doc/old-posts/0008-concerning-the-term-monkeypatching.lt3 +105 -0
- data/doc/old-posts/0009-announcement-coming-soon.lt3 +20 -0
- data/doc/old-posts/0010-immutable-data-ditching-the-wax-tablet.lt3 +142 -0
- data/doc/old-posts/0011-computer-science-as-a-lost-art.lt3 +117 -0
- data/doc/old-posts/0012-ruby-day-in-turin-italy.lt3 +26 -0
- data/doc/old-posts/0013-rubyday-was-a-success.lt3 +28 -0
- data/doc/old-posts/0014-working-on-the-blogging-software.lt3 +42 -0
- data/doc/old-posts/0015-ok-its-not-really-a-lost-art.lt3 +137 -0
- data/doc/old-posts/0016-an-in-operator-for-ruby.lt3 +142 -0
- data/doc/old-posts/0017-the-forgotten-mathematician.lt3 +129 -0
- data/doc/old-posts/0018-ruby-puns.lt3 +31 -0
- data/doc/old-posts/0019-custom-exceptions-via-metaprogramming.lt3 +116 -0
- data/doc/old-posts/0021-trying-ror-yet-again.lt3 +35 -0
- data/doc/old-posts/0023-doctor-sleep.lt3 +43 -0
- data/doc/old-posts/0024-just-a-test.lt3 +12 -0
- data/doc/old-posts/0025-trying-another-post.lt3 +12 -0
- data/doc/old-repo +1 -0
- data/doc/reddit_integration.md +2 -2
- data/doc/user.lt3 +0 -3
- data/lib/scriptorium/api.rb +1811 -78
- data/lib/scriptorium/banner_svg.rb +55 -68
- data/lib/scriptorium/contract.rb +3 -2
- data/lib/scriptorium/exceptions.rb +133 -102
- data/lib/scriptorium/helpers.rb +282 -82
- data/lib/scriptorium/post.rb +81 -17
- data/lib/scriptorium/reddit.rb +1 -1
- data/lib/scriptorium/repo.rb +478 -164
- data/lib/scriptorium/standard_files.rb +30 -396
- data/lib/scriptorium/support/common_js/clipboard.js +35 -0
- data/lib/scriptorium/support/common_js/content-loader.js +187 -0
- data/lib/scriptorium/support/common_js/navigation.js +52 -0
- data/lib/scriptorium/support/common_js/syntax-highlighting.js +27 -0
- data/lib/scriptorium/support/config/reddit_template.txt +17 -0
- data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/social.txt +1 -0
- data/lib/scriptorium/support/highlight/css.txt +2 -0
- data/lib/scriptorium/support/highlight/custom.css +119 -0
- data/lib/scriptorium/support/highlight/js.txt +1 -0
- data/lib/scriptorium/support/post_index/config.txt +15 -0
- data/lib/scriptorium/support/post_index/style.css +55 -0
- data/lib/scriptorium/support/templates/index_entry.lt3 +16 -0
- data/{test/scriptorium-TEST-1754622690-146/themes/standard/initial/post.lt3 → lib/scriptorium/support/templates/initial_post.lt3} +5 -5
- data/lib/scriptorium/support/templates/post.lt3 +104 -0
- data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/header.txt → lib/scriptorium/support/theme/header.lt3} +1 -1
- data/lib/scriptorium/theme.rb +83 -70
- data/lib/scriptorium/version.rb +2 -2
- data/lib/scriptorium/view.rb +194 -149
- data/lib/scriptorium.rb +24 -1
- data/lib/skeleton.rb +4 -1
- data/scriptorium.gemspec +2 -1
- data/test/WEB_INTEGRATION_README.md +196 -0
- data/test/all +40 -0
- data/test/banner_svg/unit.rb +267 -35
- data/test/config/deployment.txt +5 -0
- data/test/integration/integration_test.rb +7 -7
- data/test/integration/preview_flow_test.rb +94 -0
- data/test/livetext_plugin_test.rb +453 -182
- data/test/manual/banner-tests/test01.html +82 -18
- data/test/manual/banner-tests/test02.html +82 -18
- data/test/manual/banner-tests/test03.html +82 -18
- data/test/manual/banner-tests/test04.html +89 -25
- data/test/manual/banner-tests/test05.html +89 -25
- data/test/manual/banner-tests/test06.html +89 -25
- data/test/manual/banner-tests/test07.html +89 -25
- data/test/manual/banner-tests/test08.html +82 -18
- data/test/manual/banner-tests/test09.html +82 -18
- data/test/manual/banner-tests/test10.html +82 -18
- data/test/manual/banner-tests/test11.html +82 -18
- data/test/manual/banner-tests/test12.html +82 -18
- data/test/manual/banner-tests/test13.html +82 -18
- data/test/manual/banner-tests/test14.html +82 -18
- data/test/manual/banner-tests/test15.html +82 -18
- data/test/manual/banner-tests/test16.html +82 -18
- data/test/manual/banner-tests/test17.html +82 -18
- data/test/manual/banner-tests/test18.html +90 -26
- data/test/manual/banner-tests/test19.html +90 -26
- data/test/manual/banner-tests/test20.html +90 -26
- data/test/manual/banner-tests/test21.html +90 -26
- data/test/manual/banner-tests/test22.html +90 -26
- data/test/manual/banner-tests/test23.html +90 -26
- data/test/manual/banner-tests/test24.html +90 -26
- data/test/manual/banner-tests/test25.html +89 -25
- data/test/manual/banner_environment.rb +15 -2
- data/test/manual/codemirror_demo.html +773 -0
- data/test/manual/create_posts_for_web.rb +114 -0
- data/test/manual/preview_manual_test.rb +129 -0
- data/test/manual/test_banner_features.rb +14 -14
- data/test/manual/test_banner_integration.rb +115 -0
- data/test/manual/test_banner_radial.rb +87 -0
- data/test/manual/test_syntax_highlighting.rb +60 -40
- data/test/support/preview_utils.rb +88 -0
- data/test/test_gem_assets.rb +48 -0
- data/test/test_helpers.rb +10 -0
- data/test/tui_editor_integration_test.rb +15 -15
- data/test/tui_integration_test.rb +687 -441
- data/test/unit/api.rb +757 -37
- data/test/unit/asset_management.rb +195 -221
- data/test/unit/backup_test.rb +451 -0
- data/test/unit/contract_test.rb +1 -23
- data/test/unit/core.rb +415 -61
- data/test/unit/deploy_config_test.rb +248 -0
- data/test/unit/deploy_test.rb +312 -21
- data/test/unit/edit_post_test.rb +168 -0
- data/test/unit/gem_asset_management.rb +36 -42
- data/test/unit/livetext_basic.rb +23 -35
- data/test/unit/livetext_compatibility.rb +7 -14
- data/test/unit/parse_cmd_test.rb +260 -0
- data/test/unit/{symlink_test.rb → permalink_copy_test.rb} +47 -49
- data/test/unit/post.rb +91 -26
- data/test/unit/post_index_config_test.rb +258 -0
- data/test/unit/post_state_helpers_test.rb +137 -0
- data/test/unit/read_commented_file_test.rb +8 -6
- data/test/unit/repo.rb +75 -54
- data/test/unit/social_test.rb +41 -44
- data/test/unit/syntax_highlighting.rb +70 -0
- data/test/unit/theme_management_test.rb +91 -0
- data/test/unit/view.rb +79 -12
- data/test/unit/widgets.rb +8 -8
- data/test/web_integration_test.rb +231 -0
- data/test/web_test_helper.rb +218 -0
- data/test/web_workflow_test.rb +527 -0
- data/ui/tui/bin/scriptorium +885 -415
- data/ui/web/app/app.rb +1398 -176
- data/ui/web/app/assets/livetext_mode.js +244 -0
- data/ui/web/app/error_helpers.rb +16 -16
- data/ui/web/app/views/advanced_config.erb +8 -2
- data/ui/web/app/views/asset_management.erb +56 -0
- data/ui/web/app/views/backup_management.erb +238 -0
- data/ui/web/app/views/config_widget.erb +232 -0
- data/ui/web/app/views/dashboard.erb +64 -72
- data/ui/web/app/views/deploy_config.erb +3 -0
- data/ui/web/app/views/edit_pages.erb +170 -2
- data/ui/web/app/views/edit_post.erb +130 -9
- data/ui/web/app/views/edit_theme.erb +73 -0
- data/ui/web/app/views/edit_theme_file.erb +74 -0
- data/ui/web/app/views/theme_management.erb +130 -0
- data/ui/web/app/views/view_dashboard.erb +666 -25
- data/ui/web/app/views/widgets.erb +249 -0
- data/ui/web/bin/scriptorium-web +35 -24
- data/ui/web/tmp/timing.log +17 -0
- data/ui/web/tmp/web_server.log +0 -5
- metadata +190 -116
- data/assets/back-icon.png +0 -0
- data/assets/icons/facebook.svg +0 -1
- data/assets/icons/github.svg +0 -1
- data/assets/icons/instagram.svg +0 -1
- data/assets/icons/reddit.svg +0 -1
- data/assets/icons/x.svg +0 -1
- data/assets/icons/youtube.svg +0 -1
- data/bin/scriptorium +0 -1511
- data/doc/anti-amnesia/20250727-060000-api-design-tui-planning.md +0 -34
- data/doc/anti-amnesia/20250727-061000-runeblog-tui-analysis.md +0 -50
- data/doc/anti-amnesia/20250727-154000-livetext-plugin-file-stats.md +0 -73
- data/doc/anti-amnesia/20250727-172600-unified-minitest-framework.md +0 -70
- data/doc/anti-amnesia/20250727-173000-widget-testing-achievement.md +0 -110
- data/doc/anti-amnesia/20250727-180000-post-id-num-refactoring.md +0 -73
- data/doc/anti-amnesia/20250728-124421-conversation-summary-concise.md +0 -124
- data/doc/anti-amnesia/20250729-190000-scriptorium-tui-testing-complete.md +0 -46
- data/doc/anti-amnesia/20250729-200000-scriptorium-tui-testing-edit-file-workflow.md +0 -97
- data/doc/anti-amnesia/20250729-211500-dependency-management-system.md +0 -211
- data/doc/anti-amnesia/20250729-213000-python-virtual-environment-setup.md +0 -141
- data/doc/anti-amnesia/20250729-214500-theme-management-commands.md +0 -211
- data/doc/anti-amnesia/20250729-215000-version-update-to-0.6.0.md +0 -134
- data/doc/anti-amnesia/20250729-220000-user-guide-complete.md +0 -41
- data/doc/anti-amnesia/20250804-213700-publishing-test-fix.md +0 -49
- data/doc/anti-amnesia/20250804-214400-additional-test-fixes.md +0 -46
- data/doc/anti-amnesia/20250804-220000-asset-function-logic-clarification.md +0 -41
- data/doc/anti-amnesia/20250806-202032-asset-function-logic-clarification.md +0 -41
- data/doc/anti-amnesia/20250813-082428-syntax-highlighting-and-navigation-improvements.md +0 -256
- data/lib/scriptorium/syntax_highlighter.rb +0 -234
- data/test/manual/deploy_symlink_demo.rb +0 -142
- data/test/manual/symlink_demo.rb +0 -117
- data/test/manual/test2.rb +0 -12
- data/test/manual/test_banner_from_file.rb +0 -150
- data/test/manual/test_banner_in_header.rb +0 -35
- data/test/manual/test_code_highlighting.rb +0 -68
- data/test/manual/test_complex_header.rb +0 -74
- data/test/manual/test_empty_header.rb +0 -32
- data/test/manual/test_radial_custom.rb +0 -58
- data/test/manual/test_radial_large_radius.rb +0 -52
- data/test/manual/test_svg_debug.rb +0 -47
- data/test/pages-demo/config/currentview.txt +0 -1
- data/test/pages-demo/views/demo/config/common.js +0 -57
- data/test/pages-demo/views/demo/config/footer.txt +0 -1
- data/test/pages-demo/views/demo/config/global-head.txt +0 -8
- data/test/pages-demo/views/demo/config/header.txt +0 -1
- data/test/pages-demo/views/demo/config/layout.txt +0 -1
- data/test/pages-demo/views/demo/config/left.txt +0 -1
- data/test/pages-demo/views/demo/config/main.txt +0 -1
- data/test/pages-demo/views/demo/config/right.txt +0 -1
- data/test/pages-demo/views/demo/config.txt +0 -3
- data/test/pages-demo/views/demo/output/panes/footer.html +0 -1
- data/test/pages-demo/views/demo/output/panes/header.html +0 -1
- data/test/pages-demo/views/demo/output/panes/left.html +0 -1
- data/test/pages-demo/views/demo/output/panes/main.html +0 -1
- data/test/pages-demo/views/demo/output/panes/right.html +0 -1
- data/test/scriptorium-TEST-1754622690-146/config/bootstrap_css.txt +0 -5
- data/test/scriptorium-TEST-1754622690-146/config/bootstrap_js.txt +0 -4
- data/test/scriptorium-TEST-1754622690-146/config/common.js +0 -57
- data/test/scriptorium-TEST-1754622690-146/config/currentview.txt +0 -1
- data/test/scriptorium-TEST-1754622690-146/config/global-head.txt +0 -9
- data/test/scriptorium-TEST-1754622690-146/config/last_post_num.txt +0 -1
- data/test/scriptorium-TEST-1754622690-146/config/os_helpers.rb +0 -4
- data/test/scriptorium-TEST-1754622690-146/config/widgets.txt +0 -3
- data/test/scriptorium-TEST-1754622690-146/posts/0001/meta.txt +0 -8
- data/test/scriptorium-TEST-1754622690-146/posts/0001/source.lt3 +0 -6
- data/test/scriptorium-TEST-1754622690-146/themes/standard/README.txt +0 -1
- data/test/scriptorium-TEST-1754622690-146/themes/standard/config.txt +0 -1
- data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/gen/text.css +0 -1
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index.lt3 +0 -1
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index_entry.lt3 +0 -14
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/post.lt3 +0 -13
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/widget.lt3 +0 -1
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_css.txt +0 -5
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_js.txt +0 -4
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/common.js +0 -57
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/deploy.txt +0 -5
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/footer.txt +0 -2
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/global-head.txt +0 -9
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/header.txt +0 -4
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/layout.txt +0 -5
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/left.txt +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/main.txt +0 -5
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/right.txt +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/status.txt +0 -7
- data/test/scriptorium-TEST-1754622690-146/views/sample/config.txt +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/footer.html +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/header.html +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/left.html +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/main.html +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/right.html +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/footer.html +0 -1
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/header.html +0 -1
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/left.html +0 -1
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/main.html +0 -1
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/right.html +0 -1
- data/ui/web/tmp/web_server.pid +0 -1
- /data/{test/pages-demo/views/demo/config/bootstrap_css.txt → lib/scriptorium/support/bootstrap/css.txt} +0 -0
- /data/{test/pages-demo/views/demo/config/bootstrap_js.txt → lib/scriptorium/support/bootstrap/js.txt} +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/reddit.txt +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout → lib/scriptorium/support/templates}/layout.txt +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/footer.txt → lib/scriptorium/support/theme/footer.lt3} +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/left.txt → lib/scriptorium/support/theme/left.lt3} +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/main.txt → lib/scriptorium/support/theme/main.lt3} +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/right.txt → lib/scriptorium/support/theme/right.lt3} +0 -0
- /data/test/manual/banner-tests/{config.txt → svg.txt} +0 -0
- /data/test/manual/{test6.rb → test_advanced_widgets.rb} +0 -0
- /data/test/manual/{test1.rb → test_basic_posts.rb} +0 -0
- /data/test/manual/{test4.rb → test_layout_widgets.rb} +0 -0
- /data/test/manual/{test5.rb → test_pagination.rb} +0 -0
- /data/test/manual/{test3.rb → test_random_posts.rb} +0 -0
@@ -0,0 +1,187 @@
|
|
1
|
+
// Simple cache for index fragment to make Back instant in SPA
|
2
|
+
let __indexFragmentCache = null;
|
3
|
+
|
4
|
+
// Load the main content and other page containers (header, footer, left, right)
|
5
|
+
function load_main(slug) {
|
6
|
+
// (timing removed)
|
7
|
+
// Determine preview root (/preview/<view>/) for absolute fetches
|
8
|
+
const pathParts = window.location.pathname.split('/');
|
9
|
+
const previewIdx = pathParts.indexOf('preview');
|
10
|
+
const viewName = (previewIdx >= 0 && pathParts.length > previewIdx + 1) ? pathParts[previewIdx + 1] : '';
|
11
|
+
const previewRoot = `/preview/${viewName}/`;
|
12
|
+
// Get all container elements (header, footer, left, right, and main)
|
13
|
+
const contentDiv = document.getElementById("main");
|
14
|
+
const headerDiv = document.querySelector("header");
|
15
|
+
const footerDiv = document.querySelector("footer");
|
16
|
+
const leftDiv = document.querySelector(".left");
|
17
|
+
const rightDiv = document.querySelector(".right");
|
18
|
+
console.log('Loading main with slug:', slug); // Log the slug
|
19
|
+
|
20
|
+
// Clear any existing content to prevent nesting
|
21
|
+
contentDiv.innerHTML = '';
|
22
|
+
contentDiv.dataset.currentSlug = slug;
|
23
|
+
|
24
|
+
// Check if this is a post parameter request
|
25
|
+
if (slug.includes('?post=')) {
|
26
|
+
const postSlug = slug.split('?post=')[1];
|
27
|
+
console.log('Loading post:', postSlug);
|
28
|
+
|
29
|
+
// Load the post content from preview root
|
30
|
+
const postFile = postSlug.endsWith('.html') ? postSlug : postSlug + '.html';
|
31
|
+
const postUrl = previewRoot + 'posts/' + postFile;
|
32
|
+
console.log('Fetching post file:', postUrl);
|
33
|
+
// Proactively prefetch index fragment to make Back instant
|
34
|
+
if (!__indexFragmentCache) {
|
35
|
+
fetch(previewRoot + 'post_index.html').then(r => r.ok ? r.text() : '').then(t => { if (t) { __indexFragmentCache = t; } }).catch(() => {});
|
36
|
+
}
|
37
|
+
fetch(postUrl)
|
38
|
+
.then(response => {
|
39
|
+
console.log('Response status:', response.status);
|
40
|
+
if (response.ok) {
|
41
|
+
return response.text();
|
42
|
+
} else {
|
43
|
+
console.error('Failed to load post:', response.status);
|
44
|
+
return 'Post not found';
|
45
|
+
}
|
46
|
+
})
|
47
|
+
.then(content => {
|
48
|
+
console.log('Loaded content length:', content.length);
|
49
|
+
console.log('Content preview:', content.substring(0, 200));
|
50
|
+
contentDiv.innerHTML = content;
|
51
|
+
// Intercept Back link to return to index within SPA
|
52
|
+
try {
|
53
|
+
contentDiv.querySelectorAll('a[href]').forEach(a => {
|
54
|
+
const href = a.getAttribute('href') || '';
|
55
|
+
if (href === 'index.html' || href.endsWith('/index.html') || href === '../index.html') {
|
56
|
+
a.addEventListener('click', function(ev) {
|
57
|
+
ev.preventDefault();
|
58
|
+
// Fast path: render cached index if available
|
59
|
+
if (__indexFragmentCache) {
|
60
|
+
contentDiv.innerHTML = __indexFragmentCache;
|
61
|
+
history.pushState({slug: 'index.html'}, "", 'index.html');
|
62
|
+
} else {
|
63
|
+
load_main('index.html');
|
64
|
+
}
|
65
|
+
});
|
66
|
+
}
|
67
|
+
});
|
68
|
+
} catch (e) { console.warn('Back link interception skipped:', e); }
|
69
|
+
// Fix relative asset URLs (e.g., ../assets or ../../assets) to preview route
|
70
|
+
try {
|
71
|
+
const parts = window.location.pathname.split('/');
|
72
|
+
const idx = parts.indexOf('preview');
|
73
|
+
const viewName = idx >= 0 && parts.length > idx + 1 ? parts[idx + 1] : '';
|
74
|
+
const baseAssets = `/preview/${viewName}/assets/`;
|
75
|
+
// Update img[src]
|
76
|
+
contentDiv.querySelectorAll('img[src]').forEach(img => {
|
77
|
+
const s = img.getAttribute('src');
|
78
|
+
const m = s && s.match(/^(?:\.\.\/)+assets\/(.*)$/);
|
79
|
+
if (m) { img.setAttribute('src', baseAssets + m[1]); }
|
80
|
+
});
|
81
|
+
// Update link[href] (e.g., styles or anchors that point into assets)
|
82
|
+
contentDiv.querySelectorAll('a[href], link[href]').forEach(a => {
|
83
|
+
const s = a.getAttribute('href');
|
84
|
+
const m = s && s.match(/^(?:\.\.\/)+assets\/(.*)$/);
|
85
|
+
if (m) { a.setAttribute('href', baseAssets + m[1]); }
|
86
|
+
});
|
87
|
+
// Update script[src]
|
88
|
+
contentDiv.querySelectorAll('script[src]').forEach(sc => {
|
89
|
+
const s = sc.getAttribute('src');
|
90
|
+
const m = s && s.match(/^(?:\.\.\/)+assets\/(.*)$/);
|
91
|
+
if (m) { sc.setAttribute('src', baseAssets + m[1]); }
|
92
|
+
});
|
93
|
+
} catch (e) {
|
94
|
+
console.warn('Asset URL rewrite skipped:', e);
|
95
|
+
}
|
96
|
+
|
97
|
+
// Debug: Check what pre elements exist
|
98
|
+
const allPreElements = contentDiv.querySelectorAll('pre');
|
99
|
+
console.log('All pre elements found:', allPreElements.length);
|
100
|
+
allPreElements.forEach((pre, index) => {
|
101
|
+
console.log(`Pre element ${index}:`, pre.outerHTML.substring(0, 100));
|
102
|
+
});
|
103
|
+
|
104
|
+
// Highlight the newly loaded content
|
105
|
+
highlightNewContent(contentDiv);
|
106
|
+
|
107
|
+
// (detailed timing removed)
|
108
|
+
|
109
|
+
history.pushState({slug: 'index.html?post=' + postSlug}, "", 'index.html?post=' + postSlug);
|
110
|
+
// (timing removed)
|
111
|
+
})
|
112
|
+
.catch(error => {
|
113
|
+
console.log("Error loading post:", error);
|
114
|
+
contentDiv.innerHTML = 'Error loading post';
|
115
|
+
});
|
116
|
+
return;
|
117
|
+
}
|
118
|
+
|
119
|
+
// Check if this is a static page request (pages/, assets/, etc.)
|
120
|
+
if (slug.startsWith('pages/') || slug.startsWith('assets/') || slug.includes('/')) {
|
121
|
+
console.log('Loading static page:', slug);
|
122
|
+
// Fetch from preview root to avoid base href side-effects
|
123
|
+
fetch(previewRoot + slug)
|
124
|
+
.then(response => {
|
125
|
+
if (response.ok) {
|
126
|
+
return response.text();
|
127
|
+
} else {
|
128
|
+
console.error('Failed to load static page:', response.status);
|
129
|
+
return 'Page not found';
|
130
|
+
}
|
131
|
+
})
|
132
|
+
.then(content => {
|
133
|
+
contentDiv.innerHTML = content;
|
134
|
+
// Don't change the URL for static pages to avoid path resolution issues
|
135
|
+
history.pushState({slug: slug}, "", window.location.pathname);
|
136
|
+
})
|
137
|
+
.catch(error => {
|
138
|
+
console.log("Error loading static page:", error);
|
139
|
+
contentDiv.innerHTML = 'Error loading page';
|
140
|
+
});
|
141
|
+
return;
|
142
|
+
}
|
143
|
+
|
144
|
+
// If asked for index.html, prefer cached post index fragment for instant load
|
145
|
+
if (slug === 'index.html' && __indexFragmentCache) {
|
146
|
+
contentDiv.innerHTML = __indexFragmentCache;
|
147
|
+
history.pushState({slug: slug}, "", 'index.html');
|
148
|
+
return;
|
149
|
+
}
|
150
|
+
|
151
|
+
// Otherwise, fetch target (index fragment or other resource)
|
152
|
+
const target = (slug === 'index.html') ? (previewRoot + 'post_index.html') : (previewRoot + slug);
|
153
|
+
fetch(target)
|
154
|
+
.then(response => {
|
155
|
+
if (response.ok) {
|
156
|
+
console.log('Response is ok');
|
157
|
+
return response.text();
|
158
|
+
} else {
|
159
|
+
console.error('Failed to load:', response.status); // Log the failed response
|
160
|
+
}
|
161
|
+
})
|
162
|
+
.then(content => {
|
163
|
+
console.log('Loaded content into div'); // Log successful content insertion
|
164
|
+
|
165
|
+
// Inject into main container only
|
166
|
+
contentDiv.innerHTML = content;
|
167
|
+
if (slug === 'index.html' && content) { __indexFragmentCache = content; }
|
168
|
+
|
169
|
+
// Re-insert header, footer, left, and right (if necessary)
|
170
|
+
// If you want the static layout to be kept, you can preserve these parts
|
171
|
+
// with additional logic or predefined structure (here it's assumed
|
172
|
+
// that header/footer/left/right are already statically included).
|
173
|
+
|
174
|
+
// You can also replace the other parts (left, right, header, footer) if needed.
|
175
|
+
// Keep URL stable at index.html for index view, otherwise reflect the slug
|
176
|
+
const newUrl = (slug === 'index.html') ? 'index.html' : slug;
|
177
|
+
|
178
|
+
// Detailed timing for index fragment
|
179
|
+
// (detailed timing removed)
|
180
|
+
|
181
|
+
history.pushState({slug: slug}, "", newUrl);
|
182
|
+
// (timing removed)
|
183
|
+
})
|
184
|
+
.catch(error => {
|
185
|
+
console.log("Error loading content:", error); // Log any errors during fetch
|
186
|
+
});
|
187
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
// Handle the back/forward buttons with SPA-aware loading
|
2
|
+
window.onpopstate = function(event) {
|
3
|
+
try {
|
4
|
+
console.log('onpopstate event:', event);
|
5
|
+
const state = event.state || {};
|
6
|
+
const slug = state.slug || 'index.html';
|
7
|
+
// Use SPA loader to restore prior view instead of reloading
|
8
|
+
if (typeof load_main === 'function') {
|
9
|
+
load_main(slug);
|
10
|
+
return;
|
11
|
+
}
|
12
|
+
} catch (e) {
|
13
|
+
console.warn('onpopstate handler failed, reloading:', e);
|
14
|
+
}
|
15
|
+
// Fallback
|
16
|
+
window.location.reload();
|
17
|
+
};
|
18
|
+
|
19
|
+
// Initialize with the front page when navigating via the back button or similar
|
20
|
+
window.onload = function() {
|
21
|
+
// If under preview, set a base href so relative assets in injected posts resolve correctly
|
22
|
+
try {
|
23
|
+
const parts = window.location.pathname.split('/');
|
24
|
+
const idx = parts.indexOf('preview');
|
25
|
+
if (idx >= 0 && parts.length > idx + 1) {
|
26
|
+
const viewName = parts[idx + 1];
|
27
|
+
const base = document.createElement('base');
|
28
|
+
// Base at /preview/<view>/ so relative paths behave consistently with production
|
29
|
+
base.setAttribute('href', `/preview/${viewName}/`);
|
30
|
+
document.head.insertBefore(base, document.head.firstChild);
|
31
|
+
}
|
32
|
+
} catch (e) { console.warn('Base href insertion skipped:', e); }
|
33
|
+
|
34
|
+
// Check if the URL has a post parameter and load it automatically
|
35
|
+
const urlParams = new URLSearchParams(window.location.search);
|
36
|
+
const postParam = urlParams.get('post');
|
37
|
+
|
38
|
+
if (postParam) {
|
39
|
+
// URL has a post parameter, load the post content
|
40
|
+
console.log('Auto-loading post from URL parameter:', postParam);
|
41
|
+
load_main('index.html?post=' + postParam);
|
42
|
+
return;
|
43
|
+
}
|
44
|
+
|
45
|
+
// Check if the initial state exists, if not, set it
|
46
|
+
if (!history.state) {
|
47
|
+
// Don't try to load post_index.html if there are no posts
|
48
|
+
// The "No posts yet!" message is already in the main container
|
49
|
+
history.replaceState({ slug: "index.html" }, "", "index.html");
|
50
|
+
}
|
51
|
+
// (timing removed)
|
52
|
+
};
|
@@ -0,0 +1,27 @@
|
|
1
|
+
// Highlight newly loaded content
|
2
|
+
function highlightNewContent(container) {
|
3
|
+
if (typeof hljs !== 'undefined') {
|
4
|
+
// Find all code blocks in the new content and highlight them
|
5
|
+
const codeBlocks = container.querySelectorAll('pre code[class*="language-"]');
|
6
|
+
console.log('Found code blocks:', codeBlocks.length);
|
7
|
+
if (codeBlocks.length > 0) {
|
8
|
+
// Highlight each code block
|
9
|
+
codeBlocks.forEach((codeBlock, index) => {
|
10
|
+
console.log(`Highlighting code block ${index}:`, codeBlock);
|
11
|
+
try {
|
12
|
+
hljs.highlightElement(codeBlock);
|
13
|
+
console.log(`Successfully highlighted code block ${index}`);
|
14
|
+
} catch (error) {
|
15
|
+
console.error(`Error highlighting code block ${index}:`, error);
|
16
|
+
}
|
17
|
+
});
|
18
|
+
}
|
19
|
+
} else {
|
20
|
+
console.log('hljs is not defined');
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
// Initialize highlight.js syntax highlighting
|
25
|
+
if (typeof hljs !== 'undefined') {
|
26
|
+
hljs.highlightAll();
|
27
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Reddit config data
|
2
|
+
|
3
|
+
# App information
|
4
|
+
|
5
|
+
user_agent Scriptorium Blog Bot 1.0 by /u/hal_fulton
|
6
|
+
client_id 7UpmDm8vg6v-mzuwyGcSUg
|
7
|
+
secret BsIXzKihItxEP6PtxGVl9ThXi4qEYw
|
8
|
+
|
9
|
+
# Your reddit login
|
10
|
+
|
11
|
+
username YOUR_REDDIT_USERNAME
|
12
|
+
password YOUR_REDDIT_PASSWORD
|
13
|
+
|
14
|
+
# Community (subreddit) where you'll post
|
15
|
+
|
16
|
+
subreddit YOUR_SUBREDDIT_NAME
|
17
|
+
|
@@ -0,0 +1,119 @@
|
|
1
|
+
<style>
|
2
|
+
pre {
|
3
|
+
max-height: none !important;
|
4
|
+
height: auto !important;
|
5
|
+
overflow: visible !important;
|
6
|
+
background: #f5f2f0 !important;
|
7
|
+
padding: 1em !important;
|
8
|
+
margin: 1em 0 !important;
|
9
|
+
border-radius: 0.3em !important;
|
10
|
+
display: block !important;
|
11
|
+
}
|
12
|
+
pre code {
|
13
|
+
white-space: pre-wrap !important;
|
14
|
+
word-wrap: break-word !important;
|
15
|
+
display: block !important;
|
16
|
+
}
|
17
|
+
pre code tt {
|
18
|
+
white-space: normal !important;
|
19
|
+
display: inline !important;
|
20
|
+
}
|
21
|
+
code {
|
22
|
+
white-space: normal;
|
23
|
+
display: inline;
|
24
|
+
}
|
25
|
+
/* Normal whitespace handling */
|
26
|
+
#main {
|
27
|
+
white-space: normal;
|
28
|
+
}
|
29
|
+
#main tt {
|
30
|
+
white-space: nowrap !important;
|
31
|
+
display: inline !important;
|
32
|
+
float: none !important;
|
33
|
+
clear: none !important;
|
34
|
+
}
|
35
|
+
tt {
|
36
|
+
white-space: nowrap !important;
|
37
|
+
display: inline !important;
|
38
|
+
float: none !important;
|
39
|
+
clear: none !important;
|
40
|
+
}
|
41
|
+
.main tt {
|
42
|
+
white-space: nowrap !important;
|
43
|
+
display: inline !important;
|
44
|
+
float: none !important;
|
45
|
+
clear: none !important;
|
46
|
+
}
|
47
|
+
p tt {
|
48
|
+
white-space: nowrap !important;
|
49
|
+
display: inline !important;
|
50
|
+
float: none !important;
|
51
|
+
clear: none !important;
|
52
|
+
}
|
53
|
+
* tt {
|
54
|
+
white-space: nowrap !important;
|
55
|
+
display: inline !important;
|
56
|
+
float: none !important;
|
57
|
+
clear: none !important;
|
58
|
+
}
|
59
|
+
body tt {
|
60
|
+
white-space: nowrap !important;
|
61
|
+
display: inline !important;
|
62
|
+
float: none !important;
|
63
|
+
clear: none !important;
|
64
|
+
}
|
65
|
+
html tt {
|
66
|
+
white-space: nowrap !important;
|
67
|
+
display: inline !important;
|
68
|
+
float: none !important;
|
69
|
+
clear: none !important;
|
70
|
+
}
|
71
|
+
p tt {
|
72
|
+
white-space: nowrap !important;
|
73
|
+
display: inline !important;
|
74
|
+
float: none !important;
|
75
|
+
clear: none !important;
|
76
|
+
}
|
77
|
+
/* Normal paragraph styling - Bootstrap isolation not needed with proper HTML */
|
78
|
+
#main p {
|
79
|
+
margin: 0 0 1em 0;
|
80
|
+
}
|
81
|
+
#main p:last-child {
|
82
|
+
margin-bottom: 0;
|
83
|
+
}
|
84
|
+
p:only-child {
|
85
|
+
display: inline !important;
|
86
|
+
}
|
87
|
+
p tt {
|
88
|
+
white-space: nowrap !important;
|
89
|
+
display: inline !important;
|
90
|
+
float: none !important;
|
91
|
+
clear: none !important;
|
92
|
+
}
|
93
|
+
/* More specific selectors to override Bootstrap */
|
94
|
+
#main p tt {
|
95
|
+
white-space: nowrap !important;
|
96
|
+
display: inline !important;
|
97
|
+
float: none !important;
|
98
|
+
clear: none !important;
|
99
|
+
}
|
100
|
+
body #main p tt {
|
101
|
+
white-space: nowrap !important;
|
102
|
+
display: inline !important;
|
103
|
+
float: none !important;
|
104
|
+
clear: none !important;
|
105
|
+
}
|
106
|
+
html body #main p tt {
|
107
|
+
white-space: nowrap !important;
|
108
|
+
display: inline !important;
|
109
|
+
float: none !important;
|
110
|
+
clear: none !important;
|
111
|
+
}
|
112
|
+
/* Ensure br elements work for paragraph spacing */
|
113
|
+
br {
|
114
|
+
display: block !important;
|
115
|
+
margin: 0 !important;
|
116
|
+
padding: 0 !important;
|
117
|
+
line-height: 1.2em !important;
|
118
|
+
}
|
119
|
+
</style>
|
@@ -0,0 +1 @@
|
|
1
|
+
src https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js
|
@@ -0,0 +1,15 @@
|
|
1
|
+
posts.per.page 10
|
2
|
+
entry.title.size 1.1em
|
3
|
+
entry.blurb.size 0.75em
|
4
|
+
entry.date.size 0.7em
|
5
|
+
entry.date.width 14%
|
6
|
+
entry.cellpadding 4
|
7
|
+
entry.margin.bottom 6px
|
8
|
+
entry.title.color #000000
|
9
|
+
entry.blurb.color #666666
|
10
|
+
entry.date.color #888888
|
11
|
+
entry.line.height 1.1
|
12
|
+
entry.date.alignment right
|
13
|
+
entry.date.spacing 0.1em
|
14
|
+
entry.date.format month dd, yyyy
|
15
|
+
index.margin.top 20px
|
@@ -0,0 +1,55 @@
|
|
1
|
+
<style>
|
2
|
+
body { font-family: verdana; line-height: 1.1 }
|
3
|
+
|
4
|
+
.recent-title a {
|
5
|
+
color: #010101;
|
6
|
+
font-family: verdana;
|
7
|
+
font-size: 28px;
|
8
|
+
float: right;
|
9
|
+
display: inline-block;
|
10
|
+
text-align: top;
|
11
|
+
text-decoration: none;
|
12
|
+
}
|
13
|
+
|
14
|
+
.recent-title a:hover {
|
15
|
+
text-decoration: none;
|
16
|
+
}
|
17
|
+
|
18
|
+
.recent-title-text a {
|
19
|
+
color: #0101a1;
|
20
|
+
font-family: verdana;
|
21
|
+
font-size: 22px;
|
22
|
+
display: block;
|
23
|
+
text-decoration: none;
|
24
|
+
}
|
25
|
+
|
26
|
+
.recent-title-text a:hover {
|
27
|
+
text-decoration: none;
|
28
|
+
}
|
29
|
+
|
30
|
+
.recent-date {
|
31
|
+
color: #9a9a9a;
|
32
|
+
font-family: verdana;
|
33
|
+
font-size: 15px;
|
34
|
+
display: block;
|
35
|
+
float: left;
|
36
|
+
text-align: top;
|
37
|
+
}
|
38
|
+
|
39
|
+
.mydrop {
|
40
|
+
color: #444444;
|
41
|
+
float: left;
|
42
|
+
text-align: top;
|
43
|
+
# font-family: Verdana;
|
44
|
+
font-size: 38px;
|
45
|
+
line-height: 38px;
|
46
|
+
# padding-top: 0px;
|
47
|
+
padding-right: 8px;
|
48
|
+
padding-left: 3px;
|
49
|
+
}
|
50
|
+
|
51
|
+
.thumbnail img {
|
52
|
+
max-height: 100%;
|
53
|
+
max-width: 100%;
|
54
|
+
}
|
55
|
+
</style>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<tr style="margin-bottom: %{entry.margin.bottom};">
|
2
|
+
<td width=%{entry.date.width} valign=top align=right>
|
3
|
+
<div style="text-align: %{entry.date.alignment}; font-size: %{entry.date.size}; color: %{entry.date.color}; line-height: %{entry.line.height};">
|
4
|
+
<div style="height: %{entry.date.spacing};"> </div>
|
5
|
+
<div>%{formatted_date}</div>
|
6
|
+
</div>
|
7
|
+
</td>
|
8
|
+
<td valign=top>
|
9
|
+
<div style="font-size: %{entry.title.size}; line-height: %{entry.line.height};">
|
10
|
+
<div><a href="javascript:void(0)"
|
11
|
+
style="text-decoration: none; color: %{entry.title.color};"
|
12
|
+
onclick="load_main('index.html?post=%{post.slug}')">%{post.title}</a></div>
|
13
|
+
<div style="font-size: %{entry.blurb.size}; color: %{entry.blurb.color};">%{post.blurb}</div>
|
14
|
+
</div>
|
15
|
+
</td>
|
16
|
+
</tr>
|
@@ -0,0 +1,104 @@
|
|
1
|
+
<!-- theme: standard -->
|
2
|
+
<style>
|
3
|
+
body { font-family: verdana; line-height: 1.1 }
|
4
|
+
|
5
|
+
/* Dropcap styles */
|
6
|
+
.dropcap {
|
7
|
+
float: left;
|
8
|
+
font-size: 3em;
|
9
|
+
line-height: 0.8;
|
10
|
+
margin: 0.1em 0.1em 0 0;
|
11
|
+
padding: 0;
|
12
|
+
font-weight: bold;
|
13
|
+
}
|
14
|
+
|
15
|
+
/* Pullquote styles */
|
16
|
+
.pullquote {
|
17
|
+
float: right;
|
18
|
+
width: 200px;
|
19
|
+
margin: 0 0 20px 20px;
|
20
|
+
padding: 15px;
|
21
|
+
background: #f5f5f5;
|
22
|
+
border-left: 4px solid #333;
|
23
|
+
font-size: 1.2em;
|
24
|
+
font-style: italic;
|
25
|
+
line-height: 1.4;
|
26
|
+
color: #666;
|
27
|
+
border-radius: 4px;
|
28
|
+
}
|
29
|
+
|
30
|
+
.pullquote-left {
|
31
|
+
float: left;
|
32
|
+
margin: 0 20px 20px 0;
|
33
|
+
}
|
34
|
+
|
35
|
+
.pullquote-right {
|
36
|
+
float: right;
|
37
|
+
margin: 0 0 20px 20px;
|
38
|
+
}
|
39
|
+
</style>
|
40
|
+
|
41
|
+
<div align='right'><a style="text-decoration: none;" href="../index.html">
|
42
|
+
<img src="../assets/icons/ui/back.png" width=32 height=32 alt="Go to Index" style="vertical-align: middle;"></img> Back to index</a>
|
43
|
+
</div>
|
44
|
+
<div style="display: flex; justify-content: space-between; align-items: baseline;">
|
45
|
+
<span style="text-align: left; font-size: 1.5em;">%{post.title}</span>
|
46
|
+
<span style="text-align: right; font-size: 0.9em;">%{reddit_button}%{post.date}</span>
|
47
|
+
</div>
|
48
|
+
<hr>
|
49
|
+
%{post.body}
|
50
|
+
<hr>
|
51
|
+
<div style="text-align: right; font-size: 0.8em;">%{post.tags}</div>
|
52
|
+
<div style="text-align: center; margin-top: 20px;">
|
53
|
+
<button onclick="copyPermalinkToClipboard(this)" style="padding: 8px 16px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer;">Copy link</button>
|
54
|
+
</div>
|
55
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
|
56
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
57
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/ruby.min.js"></script>
|
58
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/elixir.min.js"></script>
|
59
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/javascript.min.js"></script>
|
60
|
+
<script>
|
61
|
+
if (typeof hljs !== 'undefined') { hljs.highlightAll(); }
|
62
|
+
|
63
|
+
// If this post is injected into a container (SPA), try to highlight that container only
|
64
|
+
try {
|
65
|
+
if (typeof hljs !== 'undefined') {
|
66
|
+
var container = document.currentScript && document.currentScript.parentElement;
|
67
|
+
if (container) {
|
68
|
+
container.querySelectorAll('pre code').forEach(function(el){ hljs.highlightElement(el); });
|
69
|
+
}
|
70
|
+
}
|
71
|
+
} catch (e) {}
|
72
|
+
</script>
|
73
|
+
<script>
|
74
|
+
// Fallback clipboard handler for standalone post pages if common JS isn't loaded
|
75
|
+
if (typeof copyPermalinkToClipboard === 'undefined') {
|
76
|
+
function copyPermalinkToClipboard(button) {
|
77
|
+
const currentUrl = window.location.href;
|
78
|
+
let permalinkUrl;
|
79
|
+
if (currentUrl.includes('?post=')) {
|
80
|
+
const postSlug = currentUrl.split('?post=')[1];
|
81
|
+
const parts = window.location.pathname.split('/');
|
82
|
+
parts.pop();
|
83
|
+
const baseUrl = window.location.origin + parts.join('/') + '/';
|
84
|
+
permalinkUrl = baseUrl + 'permalink/' + postSlug;
|
85
|
+
} else {
|
86
|
+
permalinkUrl = currentUrl;
|
87
|
+
}
|
88
|
+
navigator.clipboard.writeText(permalinkUrl).then(function(){
|
89
|
+
const btn = button || document.activeElement;
|
90
|
+
if (!btn) { return; }
|
91
|
+
const originalText = btn.textContent;
|
92
|
+
btn.textContent = 'Copied!';
|
93
|
+
btn.style.background = '#28a745';
|
94
|
+
setTimeout(function(){
|
95
|
+
btn.textContent = originalText;
|
96
|
+
btn.style.background = '#007bff';
|
97
|
+
}, 2000);
|
98
|
+
}).catch(function(err){
|
99
|
+
console.error('Failed to copy: ', err);
|
100
|
+
alert('Failed to copy link to clipboard');
|
101
|
+
});
|
102
|
+
}
|
103
|
+
}
|
104
|
+
</script>
|