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.
- checksums.yaml +4 -4
- data/README.lt3 +324 -0
- data/README.md +3155 -1
- data/assets/.DS_Store +0 -0
- data/assets/README.md +44 -0
- data/assets/icons/social/reddit.png +0 -0
- data/assets/icons/social/x-logo.png +0 -0
- data/assets/icons/ui/.DS_Store +0 -0
- data/assets/icons/ui/back.png +0 -0
- data/assets/icons/ui/copy.png +0 -0
- data/assets/icons/ui/down.png +0 -0
- data/assets/icons/ui/end.png +0 -0
- data/assets/icons/ui/exit.png +0 -0
- data/assets/icons/ui/foo +10 -0
- data/assets/icons/ui/home.png +0 -0
- data/assets/icons/ui/left.png +0 -0
- data/assets/icons/ui/next.png +0 -0
- data/assets/icons/ui/right.png +0 -0
- data/assets/icons/ui/start.png +0 -0
- data/assets/icons/ui/up.png +0 -0
- data/assets/imagenotfound.jpg +0 -0
- data/assets/samples/placeholder.svg +9 -0
- data/assets/themes/standard/favicon.svg +6 -0
- data/bin/sblog +84 -5
- data/bin/scriptorium +1 -0
- data/doc/README.txt +6 -0
- data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +94 -0
- data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +2 -0
- data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +45 -0
- data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +40 -0
- data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +46 -0
- data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +158 -0
- data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +35 -0
- data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +27 -0
- data/doc/anti-amnesia/20250807-213025.md +116 -0
- 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/banner_svg_config.md +114 -0
- data/doc/contrib.lt3 +8 -0
- data/doc/dependencies.md +281 -0
- data/doc/hacker.lt3 +5 -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/myuserdoc/userdoc-toc.txt +88 -0
- 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_credentials_template.json +8 -0
- data/doc/reddit_integration.md +207 -0
- data/doc/user.lt3 +35 -0
- data/doc/user_guide_section_1.md +137 -0
- data/doc/user_guide_section_10.md +515 -0
- data/doc/user_guide_section_11.md +708 -0
- data/doc/user_guide_section_2.md +233 -0
- data/doc/user_guide_section_3.md +5 -0
- data/doc/user_guide_section_4.md +221 -0
- data/doc/user_guide_section_5.md +243 -0
- data/doc/user_guide_section_6.md +147 -0
- data/doc/user_guide_section_7.md +311 -0
- data/doc/user_guide_section_8.md +224 -0
- data/doc/user_guide_section_9.md +375 -0
- data/lib/rouge/lexers/livetext.rb +74 -0
- data/lib/scriptorium/api.rb +2373 -0
- data/lib/scriptorium/banner_svg.rb +729 -0
- data/lib/scriptorium/contract.rb +34 -0
- data/lib/scriptorium/exceptions.rb +201 -1
- data/lib/scriptorium/helpers.rb +675 -0
- data/lib/scriptorium/post.rb +259 -0
- data/lib/scriptorium/reddit.rb +83 -0
- data/lib/scriptorium/repo.rb +938 -0
- data/lib/scriptorium/standard_files.rb +149 -0
- data/lib/scriptorium/support/bootstrap/css.txt +5 -0
- data/lib/scriptorium/support/bootstrap/js.txt +4 -0
- 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.txt +10 -0
- data/lib/scriptorium/support/config/reddit_template.txt +17 -0
- data/lib/scriptorium/support/config/social.txt +8 -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/lib/scriptorium/support/templates/initial_post.lt3 +12 -0
- data/lib/scriptorium/support/templates/layout.txt +5 -0
- data/lib/scriptorium/support/templates/post.lt3 +104 -0
- data/lib/scriptorium/support/theme/footer.lt3 +2 -0
- data/lib/scriptorium/support/theme/header.lt3 +4 -0
- data/lib/scriptorium/support/theme/left.lt3 +3 -0
- data/lib/scriptorium/support/theme/main.lt3 +5 -0
- data/lib/scriptorium/support/theme/right.lt3 +3 -0
- data/lib/scriptorium/theme.rb +192 -0
- data/lib/scriptorium/version.rb +1 -1
- data/lib/scriptorium/view.rb +1021 -0
- data/lib/scriptorium/widgets/featured_posts.rb +149 -0
- data/lib/scriptorium/widgets/links.rb +112 -0
- data/lib/scriptorium/widgets/pages.rb +133 -0
- data/lib/scriptorium/widgets/widget.rb +133 -0
- data/lib/scriptorium.rb +38 -34
- data/lib/skeleton.rb +10 -1
- data/scriptorium.gemspec +17 -5
- data/test/README.md +69 -0
- data/test/WEB_INTEGRATION_README.md +196 -0
- data/test/all +83 -0
- data/test/api_demo.rb +99 -0
- data/test/assets/imagenotfound.jpg +0 -0
- data/test/assets/images/.DS_Store +0 -0
- data/test/assets/images/README.md +27 -0
- data/test/assets/images/odd_aspect.png +0 -0
- data/test/assets/images/perfect.png +0 -0
- data/test/assets/images/small.png +0 -0
- data/test/assets/images/tall.png +0 -0
- data/test/assets/images/very_tall.png +0 -0
- data/test/assets/images/very_wide.png +0 -0
- data/test/assets/images/wide.png +0 -0
- data/test/assets/testbanner.jpg +0 -0
- data/test/banner_svg/simple_helpers.rb +13 -0
- data/test/banner_svg/unit.rb +1000 -0
- data/test/config/deployment.txt +5 -0
- data/test/ed_test.rb +204 -0
- data/test/integration/cursor_banner_combinations.rb +193 -0
- data/test/integration/cursor_banner_features.rb +374 -0
- data/test/integration/integration_test.rb +326 -0
- data/test/integration/preview_flow_test.rb +94 -0
- data/test/livetext_plugin_test.rb +500 -0
- data/test/manual/asset_mgmt.rb +67 -0
- data/test/manual/banner-tests/index.html +45 -0
- data/test/manual/banner-tests/svg.txt +3 -0
- data/test/manual/banner-tests/test01.html +122 -0
- data/test/manual/banner-tests/test02.html +122 -0
- data/test/manual/banner-tests/test03.html +122 -0
- data/test/manual/banner-tests/test04.html +129 -0
- data/test/manual/banner-tests/test05.html +129 -0
- data/test/manual/banner-tests/test06.html +129 -0
- data/test/manual/banner-tests/test07.html +129 -0
- data/test/manual/banner-tests/test08.html +123 -0
- data/test/manual/banner-tests/test09.html +123 -0
- data/test/manual/banner-tests/test10.html +123 -0
- data/test/manual/banner-tests/test11.html +123 -0
- data/test/manual/banner-tests/test12.html +123 -0
- data/test/manual/banner-tests/test13.html +123 -0
- data/test/manual/banner-tests/test14.html +123 -0
- data/test/manual/banner-tests/test15.html +122 -0
- data/test/manual/banner-tests/test16.html +122 -0
- data/test/manual/banner-tests/test17.html +122 -0
- data/test/manual/banner-tests/test18.html +132 -0
- data/test/manual/banner-tests/test19.html +132 -0
- data/test/manual/banner-tests/test20.html +132 -0
- data/test/manual/banner-tests/test21.html +132 -0
- data/test/manual/banner-tests/test22.html +132 -0
- data/test/manual/banner-tests/test23.html +132 -0
- data/test/manual/banner-tests/test24.html +132 -0
- data/test/manual/banner-tests/test25.html +131 -0
- data/test/manual/banner_environment.rb +205 -0
- data/test/manual/codemirror_demo.html +773 -0
- data/test/manual/create_posts_for_web.rb +114 -0
- data/test/manual/environment.rb +67 -0
- data/test/manual/make_banner.rb +153 -0
- data/test/manual/preview_manual_test.rb +129 -0
- data/test/manual/sample_banner_config.txt +12 -0
- data/test/manual/test_advanced_widgets.rb +73 -0
- data/test/manual/test_banner_combinations.rb +120 -0
- data/test/manual/test_banner_features.rb +306 -0
- data/test/manual/test_banner_integration.rb +115 -0
- data/test/manual/test_banner_radial.rb +87 -0
- data/test/manual/test_basic_posts.rb +47 -0
- data/test/manual/test_layout_widgets.rb +40 -0
- data/test/manual/test_pagination.rb +24 -0
- data/test/manual/test_random_posts.rb +38 -0
- data/test/manual/test_syntax_highlighting.rb +167 -0
- data/test/rubytext/rubytext_comprehensive_test.rb +307 -0
- data/test/rubytext/rubytext_demo_test.rb +42 -0
- data/test/rubytext/rubytext_testing_guide.md +277 -0
- data/test/run_automated_tests.rb +45 -0
- data/test/staging/.DS_Store +0 -0
- data/test/support/preview_utils.rb +88 -0
- data/test/syntax_highlighting_test.lt3 +124 -0
- data/test/test_gem_assets.rb +48 -0
- data/test/test_helpers.rb +240 -0
- data/test/tui_editor_integration_test.rb +296 -0
- data/test/tui_integration_test.rb +883 -0
- data/test/unit/api.rb +1776 -0
- data/test/unit/asset_management.rb +219 -0
- data/test/unit/backup_test.rb +451 -0
- data/test/unit/clipboard_test.rb +60 -0
- data/test/unit/contract_test.rb +69 -0
- data/test/unit/core.rb +1211 -0
- data/test/unit/deploy_config_test.rb +248 -0
- data/test/unit/deploy_test.rb +478 -0
- data/test/unit/edit_post_test.rb +168 -0
- data/test/unit/gem_asset_management.rb +183 -0
- data/test/unit/livetext_basic.rb +57 -0
- data/test/unit/livetext_compatibility.rb +82 -0
- data/test/unit/parse_cmd_test.rb +260 -0
- data/test/unit/permalink_copy_test.rb +211 -0
- data/test/unit/post.rb +309 -0
- 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 +278 -0
- data/test/unit/reddit_test.rb +235 -0
- data/test/unit/repo.rb +569 -0
- data/test/unit/social_test.rb +366 -0
- data/test/unit/syntax_highlighting.rb +70 -0
- data/test/unit/theme_management_test.rb +91 -0
- data/test/unit/view.rb +498 -0
- data/test/unit/widgets.rb +669 -0
- 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/test/wizard_test.rb +123 -0
- data/ui/README.md +67 -0
- data/ui/common/lib/ui_common.rb +8 -0
- data/ui/rubytext/README.md +191 -0
- data/ui/rubytext/bin/scriptorium-rubytext +402 -0
- data/ui/rubytext/lib/rubytext_ui.rb +300 -0
- data/ui/tui/bin/scriptorium +1890 -0
- data/ui/tui/test/tui_test.rb +23 -0
- data/ui/web/app/app.rb +2600 -0
- data/ui/web/app/assets/livetext_mode.js +244 -0
- data/ui/web/app/error_helpers.rb +150 -0
- data/ui/web/app/views/advanced_config.erb +196 -0
- data/ui/web/app/views/asset_management.erb +645 -0
- data/ui/web/app/views/backup_management.erb +238 -0
- data/ui/web/app/views/banner_config.erb +200 -0
- data/ui/web/app/views/config_widget.erb +232 -0
- data/ui/web/app/views/configure_view.erb +401 -0
- data/ui/web/app/views/dashboard.erb +154 -0
- data/ui/web/app/views/deploy_config.erb +149 -0
- data/ui/web/app/views/edit_pages.erb +363 -0
- data/ui/web/app/views/edit_post.erb +175 -0
- 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/error_page.erb +29 -0
- data/ui/web/app/views/header_config.erb +155 -0
- data/ui/web/app/views/layout_config.erb +147 -0
- data/ui/web/app/views/navbar_config.erb +411 -0
- data/ui/web/app/views/theme_management.erb +130 -0
- data/ui/web/app/views/view_dashboard.erb +779 -0
- data/ui/web/app/views/widgets.erb +249 -0
- data/ui/web/bin/scriptorium-web +164 -0
- data/ui/web/test/web_basic_test.rb +38 -0
- data/ui/web/test_navbar.txt +7 -0
- data/ui/web/tmp/timing.log +17 -0
- data/ui/web/tmp/web_server.log +0 -0
- metadata +434 -8
- data/lib/scriptorium/engine.rb +0 -22
- data/test/engine/unit.rb +0 -44
@@ -0,0 +1,244 @@
|
|
1
|
+
// Custom LiveText syntax highlighting mode for CodeMirror
|
2
|
+
CodeMirror.defineMode("livetext", function() {
|
3
|
+
return {
|
4
|
+
startState: function() {
|
5
|
+
return {
|
6
|
+
inRaw: false,
|
7
|
+
inCodeBody: false,
|
8
|
+
codeLanguage: null,
|
9
|
+
inBracket: false,
|
10
|
+
bracketDepth: 0
|
11
|
+
};
|
12
|
+
},
|
13
|
+
|
14
|
+
token: function(stream, state) {
|
15
|
+
// Skip whitespace
|
16
|
+
if (stream.eatSpace()) return null;
|
17
|
+
|
18
|
+
// Raw blocks override everything else
|
19
|
+
if (state.inRaw) {
|
20
|
+
if (stream.match(/^__RAW__/) || stream.match(/^\.end$/)) {
|
21
|
+
state.inRaw = false;
|
22
|
+
return "keyword";
|
23
|
+
}
|
24
|
+
stream.skipToEnd();
|
25
|
+
return "comment"; // Plain text in raw blocks
|
26
|
+
}
|
27
|
+
|
28
|
+
// Check for .raw command
|
29
|
+
if (stream.match(/^\.raw$/)) {
|
30
|
+
state.inRaw = true;
|
31
|
+
return "keyword";
|
32
|
+
}
|
33
|
+
|
34
|
+
// Check for .comment command
|
35
|
+
if (stream.match(/^\.comment$/)) {
|
36
|
+
state.inRaw = true; // Use same state as raw for plain text
|
37
|
+
return "keyword";
|
38
|
+
}
|
39
|
+
|
40
|
+
// Code body blocks
|
41
|
+
if (state.inCodeBody) {
|
42
|
+
if (stream.match(/^\.end$/)) {
|
43
|
+
state.inCodeBody = false;
|
44
|
+
state.codeLanguage = null;
|
45
|
+
return "keyword";
|
46
|
+
}
|
47
|
+
|
48
|
+
// Use appropriate language highlighting
|
49
|
+
if (state.codeLanguage === "ruby") {
|
50
|
+
// Ruby syntax highlighting
|
51
|
+
if (stream.match(/^#/)) {
|
52
|
+
stream.skipToEnd();
|
53
|
+
return "comment";
|
54
|
+
}
|
55
|
+
if (stream.match(/^def\b/)) return "def";
|
56
|
+
if (stream.match(/^end\b/)) return "keyword";
|
57
|
+
if (stream.match(/^class\b/)) return "def";
|
58
|
+
if (stream.match(/^module\b/)) return "def";
|
59
|
+
if (stream.match(/^require\b/)) return "keyword";
|
60
|
+
if (stream.match(/^puts\b/)) return "keyword";
|
61
|
+
if (stream.match(/^[A-Z][a-zA-Z0-9_]*/)) return "variable-2"; // Constants
|
62
|
+
if (stream.match(/^[a-z_][a-zA-Z0-9_]*/)) return "variable"; // Variables
|
63
|
+
if (stream.match(/^[0-9]+/)) return "number";
|
64
|
+
if (stream.match(/^["']/)) {
|
65
|
+
stream.skipTo(/["']/);
|
66
|
+
return "string";
|
67
|
+
}
|
68
|
+
} else if (state.codeLanguage === "elixir") {
|
69
|
+
// Elixir syntax highlighting
|
70
|
+
if (stream.match(/^#/)) {
|
71
|
+
stream.skipToEnd();
|
72
|
+
return "comment";
|
73
|
+
}
|
74
|
+
if (stream.match(/^def\b/)) return "def";
|
75
|
+
if (stream.match(/^end\b/)) return "keyword";
|
76
|
+
if (stream.match(/^defmodule\b/)) return "def";
|
77
|
+
if (stream.match(/^defp\b/)) return "def";
|
78
|
+
if (stream.match(/^IO\.puts\b/)) return "keyword";
|
79
|
+
if (stream.match(/^[A-Z][a-zA-Z0-9_]*/)) return "variable-2"; // Modules
|
80
|
+
if (stream.match(/^[a-z_][a-zA-Z0-9_]*/)) return "keyword"; // Functions
|
81
|
+
if (stream.match(/^[0-9]+/)) return "number";
|
82
|
+
if (stream.match(/^["']/)) {
|
83
|
+
stream.skipTo(/["']/);
|
84
|
+
return "string";
|
85
|
+
}
|
86
|
+
} else if (state.codeLanguage === "bash") {
|
87
|
+
// Bash syntax highlighting
|
88
|
+
if (stream.match(/^#/)) {
|
89
|
+
stream.skipToEnd();
|
90
|
+
return "comment";
|
91
|
+
}
|
92
|
+
if (stream.match(/^if\b/)) return "keyword";
|
93
|
+
if (stream.match(/^then\b/)) return "keyword";
|
94
|
+
if (stream.match(/^fi\b/)) return "keyword";
|
95
|
+
if (stream.match(/^for\b/)) return "keyword";
|
96
|
+
if (stream.match(/^do\b/)) return "keyword";
|
97
|
+
if (stream.match(/^done\b/)) return "keyword";
|
98
|
+
if (stream.match(/^\$[A-Z_]+/)) return "variable"; // Environment variables
|
99
|
+
if (stream.match(/^[0-9]+/)) return "number";
|
100
|
+
if (stream.match(/^["']/)) {
|
101
|
+
stream.skipTo(/["']/);
|
102
|
+
return "string";
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
stream.next();
|
107
|
+
return null;
|
108
|
+
}
|
109
|
+
|
110
|
+
// Check for code body commands
|
111
|
+
if (stream.match(/^\.(def|func)$/)) {
|
112
|
+
state.inCodeBody = true;
|
113
|
+
state.codeLanguage = "ruby";
|
114
|
+
return "keyword";
|
115
|
+
}
|
116
|
+
|
117
|
+
let codeMatch = stream.match(/^\.code\s+(ruby|elixir|bash)/);
|
118
|
+
if (codeMatch) {
|
119
|
+
state.inCodeBody = true;
|
120
|
+
state.codeLanguage = codeMatch[1];
|
121
|
+
return "keyword";
|
122
|
+
}
|
123
|
+
|
124
|
+
// One-line comments (. comment)
|
125
|
+
if (stream.match(/^\.\s/)) {
|
126
|
+
stream.skipToEnd();
|
127
|
+
return "comment";
|
128
|
+
}
|
129
|
+
|
130
|
+
// Dot commands (.command or $.command)
|
131
|
+
if (stream.match(/^\.\w+/)) {
|
132
|
+
return "keyword";
|
133
|
+
}
|
134
|
+
if (stream.match(/^\s+\$\.[\w.]+/)) {
|
135
|
+
return "keyword";
|
136
|
+
}
|
137
|
+
|
138
|
+
// Variables ($foo, $foo.bar) - stop at invalid characters
|
139
|
+
if (stream.match(/^\$/)) {
|
140
|
+
let name = "";
|
141
|
+
let ch = stream.next();
|
142
|
+
if (ch && /[a-zA-Z]/.test(ch)) {
|
143
|
+
name += ch;
|
144
|
+
while (stream.peek() && /[\w.]/.test(stream.peek())) {
|
145
|
+
ch = stream.next();
|
146
|
+
name += ch;
|
147
|
+
}
|
148
|
+
// Check if next character is invalid for a name
|
149
|
+
if (stream.peek() && !/[\w.]/.test(stream.peek())) {
|
150
|
+
return "variable";
|
151
|
+
}
|
152
|
+
}
|
153
|
+
return "variable";
|
154
|
+
}
|
155
|
+
|
156
|
+
// Functions ($$foo, $$foo:param, $$foo[param])
|
157
|
+
if (stream.match(/^\$\$/)) {
|
158
|
+
let name = "";
|
159
|
+
let ch = stream.next();
|
160
|
+
if (ch && /[a-zA-Z]/.test(ch)) {
|
161
|
+
name += ch;
|
162
|
+
while (stream.peek() && /[\w.]/.test(stream.peek())) {
|
163
|
+
ch = stream.next();
|
164
|
+
name += ch;
|
165
|
+
}
|
166
|
+
// Check for colon parameter
|
167
|
+
if (stream.peek() === ":") {
|
168
|
+
stream.next();
|
169
|
+
stream.skipToEnd();
|
170
|
+
}
|
171
|
+
return "function";
|
172
|
+
}
|
173
|
+
return "function";
|
174
|
+
}
|
175
|
+
|
176
|
+
// Bracketed content [content]
|
177
|
+
if (stream.match(/^\[/)) {
|
178
|
+
state.inBracket = true;
|
179
|
+
state.bracketDepth = 1;
|
180
|
+
return "bracket";
|
181
|
+
}
|
182
|
+
|
183
|
+
if (state.inBracket) {
|
184
|
+
if (stream.match(/^\]/)) {
|
185
|
+
state.inBracket = false;
|
186
|
+
state.bracketDepth = 0;
|
187
|
+
return "bracket";
|
188
|
+
}
|
189
|
+
// Continue reading bracket content
|
190
|
+
stream.next();
|
191
|
+
return "string";
|
192
|
+
}
|
193
|
+
|
194
|
+
// Bracketed formatting: *[text] _[text] `[text] ~[text]
|
195
|
+
if (stream.match(/^(\*|_|`|~)\[/)) {
|
196
|
+
state.inBracket = true;
|
197
|
+
state.bracketDepth = 1;
|
198
|
+
return "strong"; // All bracketed content gets same treatment for now
|
199
|
+
}
|
200
|
+
|
201
|
+
// Markers (* _ ` ~) - single and doubled
|
202
|
+
// Note: LiveText markers only initiate, never terminate
|
203
|
+
if (stream.match(/^\*\*/)) {
|
204
|
+
// Doubled marker - read until space, comma, or period
|
205
|
+
stream.eatWhile(/[^\s,.]/);
|
206
|
+
return "strong";
|
207
|
+
}
|
208
|
+
if (stream.match(/^__/)) {
|
209
|
+
stream.eatWhile(/[^\s,.]/);
|
210
|
+
return "em";
|
211
|
+
}
|
212
|
+
if (stream.match(/^``/)) {
|
213
|
+
stream.eatWhile(/[^\s,.]/);
|
214
|
+
return "string-2";
|
215
|
+
}
|
216
|
+
if (stream.match(/^~~/)) {
|
217
|
+
stream.eatWhile(/[^\s,.]/);
|
218
|
+
return "strikethrough";
|
219
|
+
}
|
220
|
+
|
221
|
+
// Single markers
|
222
|
+
if (stream.match(/^\*/)) {
|
223
|
+
stream.eatWhile(/[^\s]/);
|
224
|
+
return "strong";
|
225
|
+
}
|
226
|
+
if (stream.match(/^_/)) {
|
227
|
+
stream.eatWhile(/[^\s]/);
|
228
|
+
return "em";
|
229
|
+
}
|
230
|
+
if (stream.match(/^`/)) {
|
231
|
+
stream.eatWhile(/[^\s]/);
|
232
|
+
return "string-2";
|
233
|
+
}
|
234
|
+
if (stream.match(/^~/)) {
|
235
|
+
stream.eatWhile(/[^\s]/);
|
236
|
+
return "strikethrough";
|
237
|
+
}
|
238
|
+
|
239
|
+
// Continue reading
|
240
|
+
stream.next();
|
241
|
+
return null;
|
242
|
+
}
|
243
|
+
};
|
244
|
+
});
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module ErrorHelpers
|
2
|
+
# Error message mapping for common errors
|
3
|
+
ERROR_MESSAGES = {
|
4
|
+
'ReadFileNotFound' => {
|
5
|
+
message: 'File not found',
|
6
|
+
suggestion: 'The file may have been moved or deleted. Try refreshing the page or recreating the content.'
|
7
|
+
},
|
8
|
+
'PostRepoNil' => {
|
9
|
+
message: 'Repository not initialized',
|
10
|
+
suggestion: 'Please create or open a repository first.'
|
11
|
+
},
|
12
|
+
'PostNumNil' => {
|
13
|
+
message: 'Invalid post ID',
|
14
|
+
suggestion: 'Please provide a valid post number.'
|
15
|
+
},
|
16
|
+
'PostNumEmpty' => {
|
17
|
+
message: 'Post ID is empty',
|
18
|
+
suggestion: 'Please provide a valid post number.'
|
19
|
+
},
|
20
|
+
'PostNumInvalid' => {
|
21
|
+
message: 'Invalid post ID format',
|
22
|
+
suggestion: 'Post ID must be a number.'
|
23
|
+
},
|
24
|
+
'GetPostIdNil' => {
|
25
|
+
message: 'Post ID not provided',
|
26
|
+
suggestion: 'Please specify a post ID.'
|
27
|
+
},
|
28
|
+
'GetPostIdEmpty' => {
|
29
|
+
message: 'Post ID is empty',
|
30
|
+
suggestion: 'Please provide a valid post ID.'
|
31
|
+
},
|
32
|
+
'GetPostIdInvalid' => {
|
33
|
+
message: 'Invalid post ID format',
|
34
|
+
suggestion: 'Post ID must be a number.'
|
35
|
+
},
|
36
|
+
'EditFilePathNil' => {
|
37
|
+
message: 'File path not specified',
|
38
|
+
suggestion: 'Please provide a valid file path.'
|
39
|
+
},
|
40
|
+
'EditFilePathEmpty' => {
|
41
|
+
message: 'File path is empty',
|
42
|
+
suggestion: 'Please provide a valid file path.'
|
43
|
+
},
|
44
|
+
'RepoDirAlreadyExists' => {
|
45
|
+
message: 'Repository already exists',
|
46
|
+
suggestion: 'The repository directory already exists. You can open it instead.'
|
47
|
+
},
|
48
|
+
'LookupViewTargetNil' => {
|
49
|
+
message: 'View not specified',
|
50
|
+
suggestion: 'Please provide a valid view name.'
|
51
|
+
},
|
52
|
+
'ViewNameNil' => {
|
53
|
+
message: 'View name not provided',
|
54
|
+
suggestion: 'Please provide a view name.'
|
55
|
+
},
|
56
|
+
'ViewNameEmpty' => {
|
57
|
+
message: 'View name is empty',
|
58
|
+
suggestion: 'Please provide a view name.'
|
59
|
+
},
|
60
|
+
'ViewTitleNil' => {
|
61
|
+
message: 'View title not provided',
|
62
|
+
suggestion: 'Please provide a view title.'
|
63
|
+
},
|
64
|
+
'ViewTitleEmpty' => {
|
65
|
+
message: 'View title is empty',
|
66
|
+
suggestion: 'Please provide a view title.'
|
67
|
+
},
|
68
|
+
'ViewNameInvalid' => {
|
69
|
+
message: 'Invalid view name',
|
70
|
+
suggestion: 'View names can only contain letters, numbers, hyphens (-), and underscores (_).'
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
# Get a user-friendly error message
|
75
|
+
def friendly_error_message(error)
|
76
|
+
error_class = error.class.name
|
77
|
+
error_message = error.message
|
78
|
+
|
79
|
+
if ERROR_MESSAGES[error_class]
|
80
|
+
{
|
81
|
+
message: ERROR_MESSAGES[error_class][:message],
|
82
|
+
suggestion: ERROR_MESSAGES[error_class][:suggestion],
|
83
|
+
details: error_message
|
84
|
+
}
|
85
|
+
else
|
86
|
+
{
|
87
|
+
message: 'An unexpected error occurred',
|
88
|
+
suggestion: 'Please try again or contact support if the problem persists.',
|
89
|
+
details: error_message
|
90
|
+
}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Validate required parameters
|
95
|
+
def validate_required_params(params, *required_keys)
|
96
|
+
missing = required_keys.select { |key| params[key].nil? || params[key].to_s.strip.empty? }
|
97
|
+
|
98
|
+
if missing.any?
|
99
|
+
raise ArgumentError.new("Missing required parameters: #{missing.join(', ')}")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Validate post ID
|
104
|
+
def validate_post_id(post_id)
|
105
|
+
return false if post_id.nil?
|
106
|
+
return false unless post_id.to_s.match?(/^\d+$/)
|
107
|
+
return false if post_id.to_i <= 0
|
108
|
+
true
|
109
|
+
end
|
110
|
+
|
111
|
+
# Validate view name
|
112
|
+
def validate_view_name(name)
|
113
|
+
return false if name.nil?
|
114
|
+
return false if name.to_s.strip.empty?
|
115
|
+
return false unless name.to_s.match?(/^[a-zA-Z0-9_-]+$/)
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
119
|
+
# Safe file operations
|
120
|
+
def safe_read_file(path, default_content = "")
|
121
|
+
return default_content unless File.exist?(path)
|
122
|
+
File.read(path)
|
123
|
+
rescue => e
|
124
|
+
puts "Error reading file #{path}: #{e.message}" if $DEBUG
|
125
|
+
default_content
|
126
|
+
end
|
127
|
+
|
128
|
+
def safe_write_file(path, content)
|
129
|
+
FileUtils.mkdir_p(File.dirname(path))
|
130
|
+
File.write(path, content)
|
131
|
+
true
|
132
|
+
rescue => e
|
133
|
+
puts "Error writing file #{path}: #{e.message}" if $DEBUG
|
134
|
+
false
|
135
|
+
end
|
136
|
+
|
137
|
+
# Format error for display
|
138
|
+
def format_error_display(error_info)
|
139
|
+
html = "<div class='error-details'>"
|
140
|
+
html += "<strong>#{error_info[:message]}</strong><br>"
|
141
|
+
html += "<em>#{error_info[:suggestion]}</em>"
|
142
|
+
|
143
|
+
if error_info[:details] && error_info[:details] != error_info[:message]
|
144
|
+
html += "<br><small>Technical details: #{error_info[:details]}</small>"
|
145
|
+
end
|
146
|
+
|
147
|
+
html += "</div>"
|
148
|
+
html
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Advanced Configuration - <%= @current_view.name %> - 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: 800px;
|
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
|
+
text-align: center;
|
25
|
+
}
|
26
|
+
.header h1 {
|
27
|
+
margin: 0;
|
28
|
+
font-size: 24px;
|
29
|
+
}
|
30
|
+
.header p {
|
31
|
+
display: none;
|
32
|
+
}
|
33
|
+
.content {
|
34
|
+
padding: 30px;
|
35
|
+
}
|
36
|
+
.config-table {
|
37
|
+
width: 100%;
|
38
|
+
border-collapse: collapse;
|
39
|
+
}
|
40
|
+
.config-table td {
|
41
|
+
padding: 8px 0;
|
42
|
+
vertical-align: middle;
|
43
|
+
}
|
44
|
+
.config-table td:first-child {
|
45
|
+
width: 20px;
|
46
|
+
padding-right: 15px;
|
47
|
+
}
|
48
|
+
.config-table td:nth-child(2) {
|
49
|
+
width: 120px;
|
50
|
+
padding-right: 15px;
|
51
|
+
}
|
52
|
+
.config-table td:last-child {
|
53
|
+
padding-left: 0;
|
54
|
+
}
|
55
|
+
.config-item p {
|
56
|
+
margin: 0;
|
57
|
+
color: #666;
|
58
|
+
font-size: 14px;
|
59
|
+
line-height: 1.4;
|
60
|
+
flex: 1;
|
61
|
+
min-width: 0;
|
62
|
+
}
|
63
|
+
.btn {
|
64
|
+
display: inline-block;
|
65
|
+
padding: 8px 16px;
|
66
|
+
background: #007bff;
|
67
|
+
color: white;
|
68
|
+
text-decoration: none;
|
69
|
+
border-radius: 4px;
|
70
|
+
font-size: 14px;
|
71
|
+
transition: background 0.2s;
|
72
|
+
white-space: nowrap;
|
73
|
+
min-width: 120px;
|
74
|
+
text-align: center;
|
75
|
+
}
|
76
|
+
.btn {
|
77
|
+
display: inline-block;
|
78
|
+
padding: 8px 16px;
|
79
|
+
background: #007bff;
|
80
|
+
color: white;
|
81
|
+
text-decoration: none;
|
82
|
+
border-radius: 4px;
|
83
|
+
font-size: 14px;
|
84
|
+
transition: background 0.2s;
|
85
|
+
}
|
86
|
+
.btn:hover {
|
87
|
+
background: #0056b3;
|
88
|
+
}
|
89
|
+
.btn-secondary {
|
90
|
+
background: #6c757d;
|
91
|
+
}
|
92
|
+
.btn-secondary:hover {
|
93
|
+
background: #545b62;
|
94
|
+
}
|
95
|
+
.back-link {
|
96
|
+
margin-top: 20px;
|
97
|
+
text-align: center;
|
98
|
+
}
|
99
|
+
.status-indicator {
|
100
|
+
display: inline-block;
|
101
|
+
width: 8px;
|
102
|
+
height: 8px;
|
103
|
+
border-radius: 50%;
|
104
|
+
margin-right: 8px;
|
105
|
+
}
|
106
|
+
.status-active {
|
107
|
+
background: #28a745;
|
108
|
+
}
|
109
|
+
.status-inactive {
|
110
|
+
background: #dc3545;
|
111
|
+
}
|
112
|
+
</style>
|
113
|
+
</head>
|
114
|
+
<body>
|
115
|
+
<div class="container">
|
116
|
+
<div class="header">
|
117
|
+
<h1>Advanced Configuration</h1>
|
118
|
+
<p>Configure all aspects of <%= @current_view.name %></p>
|
119
|
+
</div>
|
120
|
+
|
121
|
+
<div class="content">
|
122
|
+
<table class="config-table">
|
123
|
+
<tr>
|
124
|
+
<td><span class="status-indicator status-active"></span></td>
|
125
|
+
<td><a href="#" class="btn">Update Main Settings</a></td>
|
126
|
+
<td>Configure basic view settings, title, subtitle, and other core properties.</td>
|
127
|
+
</tr>
|
128
|
+
|
129
|
+
<tr>
|
130
|
+
<td><span class="status-indicator status-active"></span></td>
|
131
|
+
<td><a href="/layout_config" class="btn">Edit Layout</a></td>
|
132
|
+
<td>Configure the overall page layout and structure.</td>
|
133
|
+
</tr>
|
134
|
+
|
135
|
+
<tr>
|
136
|
+
<td><span class="status-indicator <%= @configs[:header] ? 'status-active' : 'status-inactive' %>"></span></td>
|
137
|
+
<td><a href="/header_config" class="btn">Update Header</a></td>
|
138
|
+
<td>Set up the header structure and content for this view.</td>
|
139
|
+
</tr>
|
140
|
+
|
141
|
+
<% if @configs[:header] %>
|
142
|
+
<tr>
|
143
|
+
<td><span class="status-indicator <%= @configs[:banner] ? 'status-active' : 'status-inactive' %>"></span></td>
|
144
|
+
<td><a href="/banner_config" class="btn">Configure Banner</a></td>
|
145
|
+
<td>Customize the SVG banner with colors, fonts, and layout options.</td>
|
146
|
+
</tr>
|
147
|
+
|
148
|
+
<tr>
|
149
|
+
<td><span class="status-indicator <%= @configs[:navbar] ? 'status-active' : 'status-inactive' %>"></span></td>
|
150
|
+
<td><a href="/navbar_config" class="btn">Configure Navbar</a></td>
|
151
|
+
<td>Build the navigation menu structure with pages and sections.</td>
|
152
|
+
</tr>
|
153
|
+
<% end %>
|
154
|
+
|
155
|
+
<% if @layout_containers.include?('left') %>
|
156
|
+
<tr>
|
157
|
+
<td><span class="status-indicator status-active"></span></td>
|
158
|
+
<td><a href="#" class="btn">Update Left</a></td>
|
159
|
+
<td>Configure the left sidebar content and layout.</td>
|
160
|
+
</tr>
|
161
|
+
<% end %>
|
162
|
+
|
163
|
+
<% if @layout_containers.include?('right') %>
|
164
|
+
<tr>
|
165
|
+
<td><span class="status-indicator status-active"></span></td>
|
166
|
+
<td><a href="#" class="btn">Update Right</a></td>
|
167
|
+
<td>Configure the right sidebar content and layout.</td>
|
168
|
+
</tr>
|
169
|
+
<% end %>
|
170
|
+
|
171
|
+
<tr>
|
172
|
+
<td><span class="status-indicator status-active"></span></td>
|
173
|
+
<td><a href="/edit_pages" class="btn">Edit Pages</a></td>
|
174
|
+
<td>Create and edit content pages for this view.</td>
|
175
|
+
</tr>
|
176
|
+
|
177
|
+
<tr>
|
178
|
+
<td><span class="status-indicator status-active"></span></td>
|
179
|
+
<td><a href="/widgets" class="btn">Widget Management</a></td>
|
180
|
+
<td>Manage social media widgets and integrations for this view.</td>
|
181
|
+
</tr>
|
182
|
+
|
183
|
+
<tr>
|
184
|
+
<td><span class="status-indicator status-active"></span></td>
|
185
|
+
<td><a href="/deploy_config" class="btn">Configure Deployment</a></td>
|
186
|
+
<td>Set up server deployment settings for this view.</td>
|
187
|
+
</tr>
|
188
|
+
</table>
|
189
|
+
|
190
|
+
<div class="back-link">
|
191
|
+
<a href="/view/<%= @current_view.name %>" class="btn btn-secondary">Back to Dashboard</a>
|
192
|
+
</div>
|
193
|
+
</div>
|
194
|
+
</div>
|
195
|
+
</body>
|
196
|
+
</html>
|