stream_weaver 0.3.0
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 +7 -0
- data/.beads/.gitignore +77 -0
- data/.beads/README.md +81 -0
- data/.beads/config.yaml +54 -0
- data/.beads/metadata.json +7 -0
- data/.rspec +3 -0
- data/AGENTS.md +91 -0
- data/CHANGELOG.md +294 -0
- data/CLAUDE.md +67 -0
- data/LICENSE.txt +21 -0
- data/README.md +565 -0
- data/Rakefile +13 -0
- data/assets/streamweaver-hero.jpg +0 -0
- data/bench/baselines/ledger.rb +58 -0
- data/bench/baselines/warroom.rb +51 -0
- data/bench/fixtures/ledger.rb +76 -0
- data/bench/fixtures/warroom.rb +60 -0
- data/bench/results/6daf8b8.md +102 -0
- data/bench/results/c8d749b.md +102 -0
- data/bench/results/eb06ab9.md +102 -0
- data/bench/run.rb +151 -0
- data/bench/support.rb +84 -0
- data/copy_this/dto_run_sample_run_7631.html +220 -0
- data/docs/SERVICE_MODE.md +302 -0
- data/docs/architecture/how_streamweaver_works.md +772 -0
- data/docs/blog/2026-01-16-streamweaver-introduction.md +515 -0
- data/docs/bug-2026-08-31-canvas-bridge-socket-collision.md +83 -0
- data/docs/canvas-ipc-session-summary.md +127 -0
- data/docs/canvas-panel-workflow.md +172 -0
- data/docs/canvas-read.md +147 -0
- data/docs/canvas-roadmap.md +275 -0
- data/docs/case-studies/2026-09-03-didx-canvas-read-shelf.md +147 -0
- data/docs/claude-code-companion-skill-spec.md +567 -0
- data/docs/components_reference.md +1223 -0
- data/docs/crud-patterns.md +265 -0
- data/docs/endpoints.md +122 -0
- data/docs/for_llms.md +1 -0
- data/docs/form-patterns.md +165 -0
- data/docs/frontend-only.md +169 -0
- data/docs/html-artifact-audit.md +238 -0
- data/docs/ideas/2025-01-01-as-a-service.md +203 -0
- data/docs/ideas/2026-01-16-charm-tui-exploration.md +542 -0
- data/docs/ideas/2026-08-27-static-doc-shelf-export.md +153 -0
- data/docs/ideas/dhh-review-future-refactors.md +142 -0
- data/docs/opal-jamstack.md +47 -0
- data/docs/opal-npm-direction.md +184 -0
- data/docs/opal-spike-findings.md +194 -0
- data/docs/plans/2025-12-16-form-blocks-design.md +124 -0
- data/docs/plans/2025-12-30-examples-browser-design.md +152 -0
- data/docs/plans/2026-01-02-charts-design.md +288 -0
- data/docs/plans/2026-01-10-canvas-ipc-design.md +247 -0
- data/docs/plans/2026-01-19-cabinet-control-components.md +176 -0
- data/docs/plans/2026-01-26-gem-release-and-panel.md +140 -0
- data/docs/plans/canvas-claude-project-design.md +238 -0
- data/docs/plans/canvas-doc-location-and-discovery.md +32 -0
- data/docs/plans/org-doc-preview-surfaces.md +293 -0
- data/docs/plans/shadcn-polish-plan.md +417 -0
- data/docs/porting-artifacts.md +252 -0
- data/docs/reference/agent-skills-comparison.md +369 -0
- data/docs/reference/travel-state-prd.artifact.html +780 -0
- data/docs/research/2026-08-17-hotwire-alike-landscape.md +268 -0
- data/docs/research/2026-08-17-hotwire-concept-map.md +404 -0
- data/docs/research/2026-08-22-lazy-fragments-trigger-decision.md +246 -0
- data/docs/research/2026-08-22-learnhotwire-syllabus-coverage.md +239 -0
- data/docs/research/frontend-only-matrix.md +278 -0
- data/docs/research/streamweaver-way-spike-findings.md +529 -0
- data/docs/resource-dsl.md +342 -0
- data/docs/routing.md +302 -0
- data/docs/ruby-ui-comparison.md +319 -0
- data/docs/shared-dsl-fragments.md +356 -0
- data/docs/streamweaver-for-ai-agents.md +401 -0
- data/docs/streamweaver-frontend-vision.md +123 -0
- data/docs/streamweaver_canvas/glimmer_initial_final_layer.rb +77 -0
- data/docs/streamweaver_canvas/save_example.rb +9 -0
- data/docs/templates.md +213 -0
- data/docs/testing.md +155 -0
- data/docs/theming-hooks.md +281 -0
- data/docs/tutorials/the-streamweaver-way.md +882 -0
- data/docs/university/capability-inventory.md +137 -0
- data/docs/university/dependency-survey.md +114 -0
- data/docs/university/design-spec.md +217 -0
- data/docs/university/mockups/code-block-doc-theme-dark.png +0 -0
- data/docs/university/mockups/code-block-doc-theme-light.png +0 -0
- data/docs/university/mockups/course-list-dark.png +0 -0
- data/docs/university/mockups/course-list-light.png +0 -0
- data/docs/university/mockups/course_canvas_mockup.rb +741 -0
- data/docs/university/mockups/step-screen-dark.png +0 -0
- data/docs/university/mockups/step-screen-light.png +0 -0
- data/docs/university/roadmap.md +72 -0
- data/docs/university/send-to-coworker.md +77 -0
- data/docs/university/worker-session-mining.md +109 -0
- data/docs/visual/browser-rendering-spike.md +173 -0
- data/docs/visual/builder-visual-plan-analysis.md +378 -0
- data/docs/visual/sw-plan-format-exploration.md +511 -0
- data/docs/visual/sw-plan-rendering-deep-dive.md +453 -0
- data/docs/visual-skills/PROGRESS.md +60 -0
- data/docs/visual-skills/SESSION-CONTEXT.md +207 -0
- data/docs/visual-skills/analysis/components.md +317 -0
- data/docs/visual-skills/analysis/overlap.md +360 -0
- data/docs/visual-skills/analysis/pi-design-deck.md +1102 -0
- data/docs/visual-skills/analysis/streamweaver-inventory.md +93 -0
- data/docs/visual-skills/analysis/unified-specs.feature +1003 -0
- data/docs/visual-skills/analysis/visual-explainer.md +964 -0
- data/docs/visual-skills/blog/blog-series-outline.md +39 -0
- data/docs/visual-skills/blog/token-efficiency.md +73 -0
- data/docs/visual-skills/design/architecture.md +1725 -0
- data/docs/visual-skills/design/codex-review.md +340 -0
- data/docs/visual-skills/design/dhh-review.md +209 -0
- data/docs/visual-skills/design/evolution.md +100 -0
- data/docs/visual-skills/design/gemini-review.md +55 -0
- data/docs/visual-skills/design/review-synthesis.md +149 -0
- data/docs/visual-skills/implementation/STATE.md +22 -0
- data/docs/visual-skills/implementation/plan.md +347 -0
- data/docs/visual-skills/implementation/spike-findings.md +237 -0
- data/docs/visual-skills/implementation/tasks.md +702 -0
- data/docs/visual-skills/lessons-learned/process.md +145 -0
- data/examples/README.md +96 -0
- data/examples/advanced/all_components.rb +177 -0
- data/examples/advanced/examples_browser.rb +394 -0
- data/examples/advanced/teachables_browser.rb +261 -0
- data/examples/advanced/theme_tweaker.rb +366 -0
- data/examples/advanced/tutorial.rb +1528 -0
- data/examples/agentic/agentic_form.rb +30 -0
- data/examples/agentic/agentic_form_autoclose.rb +30 -0
- data/examples/agentic/cultivation_tracker.rb +69 -0
- data/examples/basic/hello_world.rb +22 -0
- data/examples/basic/opal_tabs_table.rb +44 -0
- data/examples/basic/todo_list.rb +39 -0
- data/examples/button_loading_test.rb +36 -0
- data/examples/canvas/mermaid_canvas_demo.sh +151 -0
- data/examples/charts/bar_chart_demo.rb +57 -0
- data/examples/charts/line_chart_demo.rb +73 -0
- data/examples/charts/pie_area_demo.rb +87 -0
- data/examples/charts/stacked_bar_chart_demo.rb +69 -0
- data/examples/claude_code/README.md +85 -0
- data/examples/claude_code/codebreaker/.claude/commands/infiltrate.md +632 -0
- data/examples/claude_code/codebreaker/.claude/settings.json +11 -0
- data/examples/claude_code/codebreaker/.claude/settings.local.json +17 -0
- data/examples/claude_code/codebreaker/.claude/skills/infiltrate.md +0 -0
- data/examples/claude_code/codebreaker/README.md +213 -0
- data/examples/claude_code/tutorial/.claude/commands/learn.md +453 -0
- data/examples/claude_code/tutorial/README.md +102 -0
- data/examples/claude_code/verification_flow/.claude/commands/verify.md +171 -0
- data/examples/claude_code/verification_flow/README.md +126 -0
- data/examples/components/annotated_code_demo.rb +54 -0
- data/examples/components/callout_demo.rb +33 -0
- data/examples/components/checkbox_group_demo.rb +46 -0
- data/examples/components/design_review.css +468 -0
- data/examples/components/design_review_demo.rb +44 -0
- data/examples/components/design_review_dsl.rb +300 -0
- data/examples/components/diff_block_demo.rb +112 -0
- data/examples/components/events_demo.rb +184 -0
- data/examples/components/form_demo.rb +62 -0
- data/examples/components/lesson_demo.rb +53 -0
- data/examples/components/markdown_demo.rb +110 -0
- data/examples/components/mermaid_demo.rb +166 -0
- data/examples/components/pareto_set.rb +64 -0
- data/examples/components/prd_demo.rb +21 -0
- data/examples/components/prd_dsl.rb +385 -0
- data/examples/components/quiz_demo.rb +47 -0
- data/examples/components/run_viewer_demo.rb +100 -0
- data/examples/components/score_and_collapsible_demo.rb +82 -0
- data/examples/components/select_stale_value_smoke_test.rb +39 -0
- data/examples/components/table_demo.rb +247 -0
- data/examples/components/timer_with_state_demo.rb +58 -0
- data/examples/components/todo_due_dates.rb +63 -0
- data/examples/components/uat_gaps_demo.rb +112 -0
- data/examples/dashboard/feed_simulator.rb +60 -0
- data/examples/dashboard/live_dashboard.rb +80 -0
- data/examples/dashboard_components.rb +108 -0
- data/examples/deferred_fragments_demo.rb +62 -0
- data/examples/generate_more_spike/README.md +63 -0
- data/examples/generate_more_spike/app.rb +441 -0
- data/examples/git_health.sh +401 -0
- data/examples/layout/layout_components_demo.rb +174 -0
- data/examples/layout/modal_demo.rb +215 -0
- data/examples/layout/navigation_demo.rb +227 -0
- data/examples/layout/route_tabs_demo.rb +52 -0
- data/examples/layout/routing_demo.rb +52 -0
- data/examples/layout/scroll_box_demo.rb +154 -0
- data/examples/lazy_fragments_demo.rb +151 -0
- data/examples/my_todos/README.md +29 -0
- data/examples/my_todos/my_todos.rb +312 -0
- data/examples/my_todos/store.rb +86 -0
- data/examples/opal/reactive_demo.rb +62 -0
- data/examples/opal/scenarios/s1_counter.rb +15 -0
- data/examples/opal/scenarios/s2_search_filter.rb +17 -0
- data/examples/opal/scenarios/s3_sibling_tabs.rb +25 -0
- data/examples/opal/scenarios/s4_shopping_cart.rb +34 -0
- data/examples/opal/scenarios/s5_watch.rb +39 -0
- data/examples/opal/scenarios/s6_on_start.rb +20 -0
- data/examples/opal/scenarios/s7_wizard.rb +33 -0
- data/examples/opal/scenarios/s8_loan_calculator.rb +21 -0
- data/examples/opal/scenarios/s9_dashboard.rb +27 -0
- data/examples/operations_dashboard_demo.rb +167 -0
- data/examples/panel_demo.sh +447 -0
- data/examples/parity/assets/tyrion_slice.css +86 -0
- data/examples/parity/rivet_people_slice.rb +182 -0
- data/examples/parity/tyrion_components.css +777 -0
- data/examples/parity/tyrion_warroom_components.rb +414 -0
- data/examples/parity/tyrion_warroom_slice.rb +549 -0
- data/examples/puma_dev/README.md +124 -0
- data/examples/puma_dev/config.ru +34 -0
- data/examples/puma_dev/standalone_app.rb +34 -0
- data/examples/scaffolding/blog.rb +49 -0
- data/examples/scaffolding/utf_lite.rb +105 -0
- data/examples/styling/feedback_demo.rb +229 -0
- data/examples/styling/style_showcase.rb +172 -0
- data/examples/styling/theme_demo.rb +508 -0
- data/examples/timer_health_checker.rb +111 -0
- data/examples/timer_showcase.rb +131 -0
- data/examples/tutorials/render_markdown.rb +112 -0
- data/examples/tutorials/streamweaver_way_tutorial.rb +44 -0
- data/examples/tutorials/tutorial_content.rb +1082 -0
- data/examples/visual_skills/design_deck_demo.rb +314 -0
- data/examples/visual_skills/explainer_demo.rb +499 -0
- data/exe/streamweaver +9 -0
- data/gsd/ROADMAP-1.0.md +167 -0
- data/gsd/STATE.md +13 -0
- data/gsd/research/market-positioning-research.md +139 -0
- data/gsd/research/production-patterns-research.md +270 -0
- data/gsd/research/repo-audit-1.0.md +274 -0
- data/lib/stream_weaver/action_token.rb +58 -0
- data/lib/stream_weaver/adapter/alpinejs.rb +8249 -0
- data/lib/stream_weaver/adapter/base.rb +591 -0
- data/lib/stream_weaver/adapter/opal.rb +334 -0
- data/lib/stream_weaver/adapter/static.rb +1118 -0
- data/lib/stream_weaver/admin.rb +176 -0
- data/lib/stream_weaver/app.rb +1821 -0
- data/lib/stream_weaver/assets/js/sw-copy.js +50 -0
- data/lib/stream_weaver/assets/js/sw-heredoc-rewrite.js +68 -0
- data/lib/stream_weaver/assets/js/sw-keyboard.js +165 -0
- data/lib/stream_weaver/assets/js/sw-mermaid-zoom.js +621 -0
- data/lib/stream_weaver/assets/js/sw-route-tabs.js +53 -0
- data/lib/stream_weaver/assets/js/sw-sidebar-toc.js +116 -0
- data/lib/stream_weaver/assets/js/sw-slide-nav.js +103 -0
- data/lib/stream_weaver/canvas/bridge.rb +239 -0
- data/lib/stream_weaver/canvas/bridge_server.rb +646 -0
- data/lib/stream_weaver/canvas/client.rb +298 -0
- data/lib/stream_weaver/canvas/doc_roots.rb +233 -0
- data/lib/stream_weaver/canvas/doc_store.rb +252 -0
- data/lib/stream_weaver/canvas/gist_publisher.rb +264 -0
- data/lib/stream_weaver/canvas/gist_save_handler.rb +89 -0
- data/lib/stream_weaver/canvas/gist_store.rb +135 -0
- data/lib/stream_weaver/canvas/helpers.rb +109 -0
- data/lib/stream_weaver/canvas/history.rb +90 -0
- data/lib/stream_weaver/canvas/protocol.rb +86 -0
- data/lib/stream_weaver/canvas/reader.rb +853 -0
- data/lib/stream_weaver/canvas/save_doc_widget.rb +457 -0
- data/lib/stream_weaver/canvas/scroll_top_hint.rb +21 -0
- data/lib/stream_weaver/canvas/session.rb +132 -0
- data/lib/stream_weaver/cli.rb +3235 -0
- data/lib/stream_weaver/component_assets.rb +70 -0
- data/lib/stream_weaver/component_registry.rb +67 -0
- data/lib/stream_weaver/component_renderer.rb +48 -0
- data/lib/stream_weaver/components/annotated_code.rb +53 -0
- data/lib/stream_weaver/components/api_endpoint.rb +42 -0
- data/lib/stream_weaver/components/callout.rb +59 -0
- data/lib/stream_weaver/components/chart.rb +84 -0
- data/lib/stream_weaver/components/code_block.rb +77 -0
- data/lib/stream_weaver/components/comparison.rb +39 -0
- data/lib/stream_weaver/components/decision.rb +38 -0
- data/lib/stream_weaver/components/deck/close_overlay.rb +84 -0
- data/lib/stream_weaver/components/deck/confirmation_bar.rb +60 -0
- data/lib/stream_weaver/components/deck/deck_option.rb +61 -0
- data/lib/stream_weaver/components/deck/deck_slide.rb +77 -0
- data/lib/stream_weaver/components/deck/deck_state.rb +469 -0
- data/lib/stream_weaver/components/deck/deck_summary.rb +73 -0
- data/lib/stream_weaver/components/deck/design_deck.rb +60 -0
- data/lib/stream_weaver/components/deck/generate_more_controls.rb +84 -0
- data/lib/stream_weaver/components/deck/model_selector.rb +84 -0
- data/lib/stream_weaver/components/deck/skeleton_placeholder.rb +36 -0
- data/lib/stream_weaver/components/diff_block.rb +125 -0
- data/lib/stream_weaver/components/doc_header.rb +57 -0
- data/lib/stream_weaver/components/image_block.rb +70 -0
- data/lib/stream_weaver/components/implementation_map.rb +33 -0
- data/lib/stream_weaver/components/keyboard_shortcuts.rb +94 -0
- data/lib/stream_weaver/components/kpi_dashboard.rb +78 -0
- data/lib/stream_weaver/components/mermaid.rb +79 -0
- data/lib/stream_weaver/components/pipeline.rb +63 -0
- data/lib/stream_weaver/components/sidebar_toc.rb +46 -0
- data/lib/stream_weaver/components/slide_container.rb +141 -0
- data/lib/stream_weaver/components/timeline_event.rb +58 -0
- data/lib/stream_weaver/components/wireframe.rb +29 -0
- data/lib/stream_weaver/components/wireframe_block.rb +34 -0
- data/lib/stream_weaver/components.rb +2711 -0
- data/lib/stream_weaver/css.rb +230 -0
- data/lib/stream_weaver/dev_fallback_overlay.rb +61 -0
- data/lib/stream_weaver/display_dsl.rb +1004 -0
- data/lib/stream_weaver/export/html_exporter.rb +478 -0
- data/lib/stream_weaver/feed.rb +34 -0
- data/lib/stream_weaver/feed_builder.rb +31 -0
- data/lib/stream_weaver/fonts.rb +33 -0
- data/lib/stream_weaver/interaction_runner.rb +487 -0
- data/lib/stream_weaver/iterm.rb +460 -0
- data/lib/stream_weaver/layout_registry.rb +92 -0
- data/lib/stream_weaver/opal/bridge.rb +52 -0
- data/lib/stream_weaver/opal/builder.rb +193 -0
- data/lib/stream_weaver/opal/env.rb +29 -0
- data/lib/stream_weaver/opal/reactive_state.rb +75 -0
- data/lib/stream_weaver/opal/regexp_anchor_patch.rb +62 -0
- data/lib/stream_weaver/opal/renderer.rb +77 -0
- data/lib/stream_weaver/opal/runtime.rb +250 -0
- data/lib/stream_weaver/opal/shell.rb +145 -0
- data/lib/stream_weaver/opal/string_bridge.rb +50 -0
- data/lib/stream_weaver/opal/stubs/diff.min.js +1 -0
- data/lib/stream_weaver/opal/stubs/digest.rb +15 -0
- data/lib/stream_weaver/opal/stubs/marked.umd.js +79 -0
- data/lib/stream_weaver/opal/stubs/md5.rb +3 -0
- data/lib/stream_weaver/opal/stubs/morphdom.min.js +775 -0
- data/lib/stream_weaver/opal/stubs/prism-tomorrow.min.css +1 -0
- data/lib/stream_weaver/opal/stubs/prism.min.js +1967 -0
- data/lib/stream_weaver/opal_entry.rb +136 -0
- data/lib/stream_weaver/org/inline.rb +95 -0
- data/lib/stream_weaver/org/reader.rb +561 -0
- data/lib/stream_weaver/org/recording_context.rb +86 -0
- data/lib/stream_weaver/org/source_splitter.rb +63 -0
- data/lib/stream_weaver/org/writer.rb +300 -0
- data/lib/stream_weaver/page_shell.rb +530 -0
- data/lib/stream_weaver/portfile.rb +79 -0
- data/lib/stream_weaver/pushable.rb +42 -0
- data/lib/stream_weaver/resource/default_views.rb +111 -0
- data/lib/stream_weaver/resource/field_input.rb +25 -0
- data/lib/stream_weaver/resource/state_keys.rb +16 -0
- data/lib/stream_weaver/resource/store.rb +18 -0
- data/lib/stream_weaver/resource.rb +104 -0
- data/lib/stream_weaver/server.rb +1471 -0
- data/lib/stream_weaver/service.rb +1240 -0
- data/lib/stream_weaver/service_client.rb +104 -0
- data/lib/stream_weaver/session_store.rb +186 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/SKILL.md +66 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/examples/canvas-safe-showcase.rb +98 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/actions-and-buttons.md +47 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/charts-and-diagrams.md +38 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/deck.md +32 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/inputs-and-forms.md +65 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/tabs-and-navigation.md +53 -0
- data/lib/stream_weaver/skills/streamweaver-doc-builder/SKILL.md +298 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/SKILL.md +130 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.css +468 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.rb +39 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example_dsl.rb +300 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example.rb +24 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example_dsl.rb +385 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/checkpoints-and-forms.md +28 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/cleanup-and-panel.md +44 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/example-gallery.md +8 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/persistence.md +58 -0
- data/lib/stream_weaver/skills/streamweaver-way/SKILL.md +396 -0
- data/lib/stream_weaver/skills/visual-plan/SKILL.md +201 -0
- data/lib/stream_weaver/skills/visual-recap/SKILL.md +244 -0
- data/lib/stream_weaver/streamer.rb +63 -0
- data/lib/stream_weaver/templates/choices.rb +149 -0
- data/lib/stream_weaver/templates/code.rb +157 -0
- data/lib/stream_weaver/templates/confirm.rb +110 -0
- data/lib/stream_weaver/templates/diff.rb +195 -0
- data/lib/stream_weaver/templates/info.rb +142 -0
- data/lib/stream_weaver/templates/table.rb +169 -0
- data/lib/stream_weaver/templates/wizard.rb +271 -0
- data/lib/stream_weaver/theme/auto_mode.rb +116 -0
- data/lib/stream_weaver/theme/presets.rb +555 -0
- data/lib/stream_weaver/theme.rb +639 -0
- data/lib/stream_weaver/university/canvas.rb +924 -0
- data/lib/stream_weaver/university/course.rb +699 -0
- data/lib/stream_weaver/university/demos/counter.rb +33 -0
- data/lib/stream_weaver/university/demos/dashboard.rb +147 -0
- data/lib/stream_weaver/university/demos/decision_form.rb +143 -0
- data/lib/stream_weaver/university/demos.rb +50 -0
- data/lib/stream_weaver/university/listener.rb +467 -0
- data/lib/stream_weaver/university/progress.rb +201 -0
- data/lib/stream_weaver/university/runner.rb +138 -0
- data/lib/stream_weaver/university/scripts/growing_doc.rb +609 -0
- data/lib/stream_weaver/university/scripts/growing_doc_state.rb +91 -0
- data/lib/stream_weaver/utils.rb +31 -0
- data/lib/stream_weaver/version.rb +5 -0
- data/lib/stream_weaver/views/canvas/reader_layout.erb +800 -0
- data/lib/stream_weaver/views.rb +3940 -0
- data/lib/stream_weaver.rb +122 -0
- data/llms.txt +1269 -0
- data/sig/stream_weaver.rbs +4 -0
- metadata +598 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Modal Demo - demonstrates modal dialogs
|
|
4
|
+
#
|
|
5
|
+
# Run with: ruby examples/modal_demo.rb
|
|
6
|
+
|
|
7
|
+
require_relative '../../lib/stream_weaver'
|
|
8
|
+
|
|
9
|
+
app = StreamWeaver.app "Modal Demo" do
|
|
10
|
+
header1 "Modal Dialogs Demo"
|
|
11
|
+
|
|
12
|
+
md "This example demonstrates **modal dialogs** with different sizes and use cases."
|
|
13
|
+
|
|
14
|
+
# Initialize state
|
|
15
|
+
state[:items] ||= ["Item 1", "Item 2", "Item 3"]
|
|
16
|
+
state[:item_to_delete] ||= nil
|
|
17
|
+
state[:form_submitted] ||= false
|
|
18
|
+
|
|
19
|
+
# =========================================
|
|
20
|
+
# Basic Modal
|
|
21
|
+
# =========================================
|
|
22
|
+
header2 "Basic Modal"
|
|
23
|
+
|
|
24
|
+
button "Open Basic Modal" do |s|
|
|
25
|
+
s[:basic_modal_open] = true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
modal :basic_modal, title: "Welcome!" do
|
|
29
|
+
text "This is a basic modal dialog."
|
|
30
|
+
md "Modals are great for:"
|
|
31
|
+
md "- Confirmations\n- Forms\n- Detailed information\n- Alerts"
|
|
32
|
+
|
|
33
|
+
modal_footer do
|
|
34
|
+
button "Got it!", style: :primary do |s|
|
|
35
|
+
s[:basic_modal_open] = false
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# =========================================
|
|
41
|
+
# Confirmation Modal
|
|
42
|
+
# =========================================
|
|
43
|
+
header2 "Confirmation Modal"
|
|
44
|
+
md "Click an item to delete it (with confirmation):"
|
|
45
|
+
|
|
46
|
+
card do
|
|
47
|
+
state[:items].each_with_index do |item, idx|
|
|
48
|
+
hstack justify: :between, align: :center do
|
|
49
|
+
text item
|
|
50
|
+
button "Delete", style: :secondary do |s|
|
|
51
|
+
s[:item_to_delete] = idx
|
|
52
|
+
s[:confirm_delete_open] = true
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if state[:items].empty?
|
|
58
|
+
text "No items. Add some below!"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
button "Add Item" do |s|
|
|
63
|
+
s[:items] << "Item #{s[:items].length + 1}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
modal :confirm_delete, title: "Confirm Delete", size: :sm do
|
|
67
|
+
text "Are you sure you want to delete this item?"
|
|
68
|
+
text "This action cannot be undone."
|
|
69
|
+
|
|
70
|
+
modal_footer do
|
|
71
|
+
button "Cancel", style: :secondary do |s|
|
|
72
|
+
s[:confirm_delete_open] = false
|
|
73
|
+
s[:item_to_delete] = nil
|
|
74
|
+
end
|
|
75
|
+
button "Delete" do |s|
|
|
76
|
+
if s[:item_to_delete]
|
|
77
|
+
s[:items].delete_at(s[:item_to_delete])
|
|
78
|
+
end
|
|
79
|
+
s[:confirm_delete_open] = false
|
|
80
|
+
s[:item_to_delete] = nil
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# =========================================
|
|
86
|
+
# Form Modal
|
|
87
|
+
# =========================================
|
|
88
|
+
header2 "Form in Modal"
|
|
89
|
+
|
|
90
|
+
button "Open Form Modal" do |s|
|
|
91
|
+
s[:form_modal_open] = true
|
|
92
|
+
s[:form_submitted] = false
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
if state[:form_submitted]
|
|
96
|
+
card do
|
|
97
|
+
text "Form submitted!"
|
|
98
|
+
text "Name: #{state[:modal_name]}"
|
|
99
|
+
text "Email: #{state[:modal_email]}"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
modal :form_modal, title: "Contact Form", size: :md do
|
|
104
|
+
text "Fill out the form below:"
|
|
105
|
+
|
|
106
|
+
text_field :modal_name, placeholder: "Your name"
|
|
107
|
+
text_field :modal_email, placeholder: "your@email.com"
|
|
108
|
+
text_area :modal_message, placeholder: "Your message...", rows: 3
|
|
109
|
+
|
|
110
|
+
modal_footer do
|
|
111
|
+
button "Cancel", style: :secondary do |s|
|
|
112
|
+
s[:form_modal_open] = false
|
|
113
|
+
end
|
|
114
|
+
button "Submit" do |s|
|
|
115
|
+
s[:form_submitted] = true
|
|
116
|
+
s[:form_modal_open] = false
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# =========================================
|
|
122
|
+
# Size Variations
|
|
123
|
+
# =========================================
|
|
124
|
+
header2 "Modal Sizes"
|
|
125
|
+
md "Modals come in four sizes: `:sm`, `:md` (default), `:lg`, and `:xl`"
|
|
126
|
+
|
|
127
|
+
hstack spacing: :md do
|
|
128
|
+
button "Small (sm)" do |s|
|
|
129
|
+
s[:size_sm_open] = true
|
|
130
|
+
end
|
|
131
|
+
button "Medium (md)" do |s|
|
|
132
|
+
s[:size_md_open] = true
|
|
133
|
+
end
|
|
134
|
+
button "Large (lg)" do |s|
|
|
135
|
+
s[:size_lg_open] = true
|
|
136
|
+
end
|
|
137
|
+
button "XL" do |s|
|
|
138
|
+
s[:size_xl_open] = true
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
modal :size_sm, title: "Small Modal", size: :sm do
|
|
143
|
+
text "This is a small modal (400px max width)."
|
|
144
|
+
text "Good for simple confirmations."
|
|
145
|
+
modal_footer do
|
|
146
|
+
button "Close" do |s|
|
|
147
|
+
s[:size_sm_open] = false
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
modal :size_md, title: "Medium Modal", size: :md do
|
|
153
|
+
text "This is a medium modal (560px max width)."
|
|
154
|
+
text "The default size, good for most use cases."
|
|
155
|
+
modal_footer do
|
|
156
|
+
button "Close" do |s|
|
|
157
|
+
s[:size_md_open] = false
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
modal :size_lg, title: "Large Modal", size: :lg do
|
|
163
|
+
text "This is a large modal (800px max width)."
|
|
164
|
+
text "Good for forms with more fields or detailed content."
|
|
165
|
+
md "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
|
166
|
+
modal_footer do
|
|
167
|
+
button "Close" do |s|
|
|
168
|
+
s[:size_lg_open] = false
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
modal :size_xl, title: "Extra Large Modal", size: :xl do
|
|
174
|
+
text "This is an extra large modal (1140px max width)."
|
|
175
|
+
text "Good for complex content like data tables or multi-column layouts."
|
|
176
|
+
|
|
177
|
+
columns widths: ['50%', '50%'] do
|
|
178
|
+
column do
|
|
179
|
+
header4 "Left Column"
|
|
180
|
+
text "Some content on the left side."
|
|
181
|
+
text_field :xl_field_1, placeholder: "Field 1"
|
|
182
|
+
end
|
|
183
|
+
column do
|
|
184
|
+
header4 "Right Column"
|
|
185
|
+
text "Some content on the right side."
|
|
186
|
+
text_field :xl_field_2, placeholder: "Field 2"
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
modal_footer do
|
|
191
|
+
button "Close" do |s|
|
|
192
|
+
s[:size_xl_open] = false
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# =========================================
|
|
198
|
+
# Usage notes
|
|
199
|
+
# =========================================
|
|
200
|
+
md """
|
|
201
|
+
---
|
|
202
|
+
**How it works:**
|
|
203
|
+
- Modals use state key `:{modal_key}_open` to control visibility
|
|
204
|
+
- Set to `true` to open, `false` to close
|
|
205
|
+
- Close by: clicking backdrop, pressing Escape, or button action
|
|
206
|
+
- Sizes: `:sm` (400px), `:md` (560px), `:lg` (800px), `:xl` (1140px)
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
md "---"
|
|
210
|
+
button "Reset Demo", style: :secondary do |s|
|
|
211
|
+
s.clear
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
app.run!
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Navigation Components Demo
|
|
4
|
+
# Demonstrates Tabs, Breadcrumbs, and Dropdown/Menu components
|
|
5
|
+
#
|
|
6
|
+
# Run with: ruby -r ./lib/stream_weaver examples/navigation_demo.rb
|
|
7
|
+
|
|
8
|
+
require_relative '../../lib/stream_weaver'
|
|
9
|
+
|
|
10
|
+
app "Navigation Components", layout: :wide do
|
|
11
|
+
header "Navigation Components Demo"
|
|
12
|
+
text "This demo showcases the Phase 2 navigation components: Tabs, Breadcrumbs, and Dropdown menus."
|
|
13
|
+
|
|
14
|
+
# =========================================
|
|
15
|
+
# Breadcrumbs
|
|
16
|
+
# =========================================
|
|
17
|
+
header2 "Breadcrumbs"
|
|
18
|
+
text "Navigate hierarchical content with breadcrumb trails."
|
|
19
|
+
|
|
20
|
+
breadcrumbs do
|
|
21
|
+
crumb "Home", href: "/"
|
|
22
|
+
crumb "Products", href: "/products"
|
|
23
|
+
crumb "Electronics", href: "/products/electronics"
|
|
24
|
+
crumb "Laptops" # Current page - no href
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
text "Custom separator:"
|
|
28
|
+
breadcrumbs separator: ">" do
|
|
29
|
+
crumb "Dashboard", href: "/dashboard"
|
|
30
|
+
crumb "Settings", href: "/settings"
|
|
31
|
+
crumb "Profile"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# =========================================
|
|
35
|
+
# Tabs - Line Variant (default)
|
|
36
|
+
# =========================================
|
|
37
|
+
header2 "Tabs - Line Variant"
|
|
38
|
+
text "Classic underline tabs - clean and minimal."
|
|
39
|
+
|
|
40
|
+
tabs :demo_tabs, variant: :line do
|
|
41
|
+
tab "Overview" do
|
|
42
|
+
card do
|
|
43
|
+
card_header "Overview Tab"
|
|
44
|
+
card_body do
|
|
45
|
+
text "This is the overview content. Tabs maintain state on the server, so switching tabs persists across page refreshes."
|
|
46
|
+
text_field :overview_input, placeholder: "Type something here..."
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
tab "Details" do
|
|
52
|
+
card do
|
|
53
|
+
card_header "Details Tab"
|
|
54
|
+
card_body do
|
|
55
|
+
text "Here are the details. Each tab can contain any StreamWeaver components."
|
|
56
|
+
vstack spacing: :sm do
|
|
57
|
+
checkbox :detail_option1, "Enable feature A"
|
|
58
|
+
checkbox :detail_option2, "Enable feature B"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
tab "Settings" do
|
|
65
|
+
card do
|
|
66
|
+
card_header "Settings Tab"
|
|
67
|
+
card_body do
|
|
68
|
+
text "Configure your preferences here."
|
|
69
|
+
select :theme, ["Light", "Dark", "System"], default: "System"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# =========================================
|
|
76
|
+
# Tabs - Enclosed Variant
|
|
77
|
+
# =========================================
|
|
78
|
+
header2 "Tabs - Enclosed Variant"
|
|
79
|
+
text "Traditional boxed tabs with borders."
|
|
80
|
+
|
|
81
|
+
tabs :enclosed_tabs, variant: :enclosed do
|
|
82
|
+
tab "First" do
|
|
83
|
+
text "Content for the first enclosed tab."
|
|
84
|
+
end
|
|
85
|
+
tab "Second" do
|
|
86
|
+
text "Content for the second enclosed tab."
|
|
87
|
+
end
|
|
88
|
+
tab "Third" do
|
|
89
|
+
text "Content for the third enclosed tab."
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# =========================================
|
|
94
|
+
# Tabs - Soft Rounded Variant
|
|
95
|
+
# =========================================
|
|
96
|
+
header2 "Tabs - Soft Rounded Variant"
|
|
97
|
+
text "Modern pill-style tabs with rounded backgrounds."
|
|
98
|
+
|
|
99
|
+
tabs :rounded_tabs, variant: :"soft-rounded" do
|
|
100
|
+
tab "All" do
|
|
101
|
+
text "Showing all items."
|
|
102
|
+
end
|
|
103
|
+
tab "Active" do
|
|
104
|
+
text "Showing only active items."
|
|
105
|
+
end
|
|
106
|
+
tab "Archived" do
|
|
107
|
+
text "Showing archived items."
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# =========================================
|
|
112
|
+
# Dropdown Menu
|
|
113
|
+
# =========================================
|
|
114
|
+
header2 "Dropdown Menu"
|
|
115
|
+
text "Click the button to reveal a dropdown menu with actions."
|
|
116
|
+
|
|
117
|
+
hstack spacing: :md, align: :center do
|
|
118
|
+
dropdown do
|
|
119
|
+
trigger do
|
|
120
|
+
button "Actions", style: :primary
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
menu do
|
|
124
|
+
menu_item "Edit" do |s|
|
|
125
|
+
s[:last_action] = "Edit clicked"
|
|
126
|
+
end
|
|
127
|
+
menu_item "Duplicate" do |s|
|
|
128
|
+
s[:last_action] = "Duplicate clicked"
|
|
129
|
+
end
|
|
130
|
+
menu_divider
|
|
131
|
+
menu_item "Archive" do |s|
|
|
132
|
+
s[:last_action] = "Archive clicked"
|
|
133
|
+
end
|
|
134
|
+
menu_item "Delete", style: :destructive do |s|
|
|
135
|
+
s[:last_action] = "Delete clicked"
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
dropdown do
|
|
141
|
+
trigger do
|
|
142
|
+
button "More Options", style: :secondary
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
menu do
|
|
146
|
+
menu_item "View Profile" do |s|
|
|
147
|
+
s[:last_action] = "View Profile clicked"
|
|
148
|
+
end
|
|
149
|
+
menu_item "Account Settings" do |s|
|
|
150
|
+
s[:last_action] = "Account Settings clicked"
|
|
151
|
+
end
|
|
152
|
+
menu_divider
|
|
153
|
+
menu_item "Sign Out", style: :destructive do |s|
|
|
154
|
+
s[:last_action] = "Sign Out clicked"
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
text -> (s) { s[:last_action] ? "Last action: #{s[:last_action]}" : "Click a menu item..." }
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# =========================================
|
|
163
|
+
# Combined Example
|
|
164
|
+
# =========================================
|
|
165
|
+
header2 "Combined Example"
|
|
166
|
+
text "Navigation components work together seamlessly."
|
|
167
|
+
|
|
168
|
+
breadcrumbs do
|
|
169
|
+
crumb "App", href: "/"
|
|
170
|
+
crumb "Users", href: "/users"
|
|
171
|
+
crumb "John Doe"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
hstack spacing: :md, justify: :between, align: :center do
|
|
175
|
+
header3 "User Profile"
|
|
176
|
+
|
|
177
|
+
dropdown do
|
|
178
|
+
trigger do
|
|
179
|
+
button "User Actions", style: :secondary
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
menu do
|
|
183
|
+
menu_item "Edit Profile" do |s|
|
|
184
|
+
s[:profile_action] = "editing"
|
|
185
|
+
end
|
|
186
|
+
menu_item "Change Password" do |s|
|
|
187
|
+
s[:profile_action] = "password"
|
|
188
|
+
end
|
|
189
|
+
menu_divider
|
|
190
|
+
menu_item "Deactivate Account", style: :destructive do |s|
|
|
191
|
+
s[:profile_action] = "deactivate"
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
tabs :user_tabs do
|
|
198
|
+
tab "Info" do
|
|
199
|
+
vstack spacing: :sm do
|
|
200
|
+
text "Name: John Doe"
|
|
201
|
+
text "Email: john@example.com"
|
|
202
|
+
text "Role: Administrator"
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
tab "Activity" do
|
|
207
|
+
text "Recent activity will be shown here."
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
tab "Permissions" do
|
|
211
|
+
checkbox_group :permissions, select_all: "Select All", select_none: "Clear" do
|
|
212
|
+
item "read" do
|
|
213
|
+
text "Read - View content"
|
|
214
|
+
end
|
|
215
|
+
item "write" do
|
|
216
|
+
text "Write - Create and edit content"
|
|
217
|
+
end
|
|
218
|
+
item "delete" do
|
|
219
|
+
text "Delete - Remove content"
|
|
220
|
+
end
|
|
221
|
+
item "admin" do
|
|
222
|
+
text "Admin - Full access"
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end.run!
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Route tabs demo: two url: true tab groups (bookmarkable, back/forward-aware)
|
|
4
|
+
# plus a deferred form to exercise the morph-does-not-revert-the-tab behavior.
|
|
5
|
+
#
|
|
6
|
+
# PORT=4573 ruby examples/layout/route_tabs_demo.rb
|
|
7
|
+
# open http://127.0.0.1:4573/?view=2&panel=1
|
|
8
|
+
require_relative "../../lib/stream_weaver"
|
|
9
|
+
|
|
10
|
+
app = StreamWeaver.app "Route Tabs Demo" do
|
|
11
|
+
header1 "Route Tabs Demo"
|
|
12
|
+
|
|
13
|
+
tabs :view, url: true do
|
|
14
|
+
tab "Overview" do
|
|
15
|
+
header3 "Overview"
|
|
16
|
+
text "The overview panel. Bookmark me with ?view=0."
|
|
17
|
+
end
|
|
18
|
+
tab "Findings" do
|
|
19
|
+
header3 "Findings"
|
|
20
|
+
text "The findings panel. Bookmark me with ?view=1."
|
|
21
|
+
end
|
|
22
|
+
tab "Details" do
|
|
23
|
+
header3 "Details"
|
|
24
|
+
text "The details panel. Bookmark me with ?view=2."
|
|
25
|
+
form :notes_form do
|
|
26
|
+
text_field :note, placeholder: "Add a note"
|
|
27
|
+
submit "Save note" do |values|
|
|
28
|
+
state[:last_note] = values[:note]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
md "Last saved note: **#{state[:last_note] || '(none)'}**"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Read BELOW the tabs declaration: above it, state[:view] still holds the raw
|
|
36
|
+
# pre-authority param (or stale session value) -- the resolved integer only
|
|
37
|
+
# exists once the group has applied URL authority.
|
|
38
|
+
md "Active view index (server-resolved): **#{state[:view].inspect}**"
|
|
39
|
+
|
|
40
|
+
md "---"
|
|
41
|
+
|
|
42
|
+
tabs :panel, url: true, variant: :enclosed do
|
|
43
|
+
tab "Alpha" do
|
|
44
|
+
text "Second group, panel Alpha (?panel=0)."
|
|
45
|
+
end
|
|
46
|
+
tab "Beta" do
|
|
47
|
+
text "Second group, panel Beta (?panel=1)."
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
app.run!(open_browser: false) if __FILE__ == $PROGRAM_NAME
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# URL Routing Demo
|
|
4
|
+
# Shows deep-linking, bookmarkable URLs, and browser back/forward
|
|
5
|
+
#
|
|
6
|
+
# Run with: ruby -r ./lib/stream_weaver examples/layout/routing_demo.rb
|
|
7
|
+
#
|
|
8
|
+
# Try:
|
|
9
|
+
# - Click nav items and watch the URL bar update
|
|
10
|
+
# - Visit /dashboard or /settings directly
|
|
11
|
+
# - Press back/forward in the browser
|
|
12
|
+
|
|
13
|
+
require_relative '../../lib/stream_weaver'
|
|
14
|
+
|
|
15
|
+
app "URL Routing Demo" do
|
|
16
|
+
route_by :page, home: "/", dashboard: "/dashboard", settings: "/settings"
|
|
17
|
+
|
|
18
|
+
state[:page] ||= :home
|
|
19
|
+
|
|
20
|
+
navbar do
|
|
21
|
+
nav_item "Home", href: "/", active: state[:page] == :home
|
|
22
|
+
nav_item "Dashboard", href: "/dashboard", active: state[:page] == :dashboard
|
|
23
|
+
nav_item "Settings", href: "/settings", active: state[:page] == :settings
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
case state[:page]
|
|
27
|
+
when :home
|
|
28
|
+
header "Home"
|
|
29
|
+
text "Welcome! Click the nav links above — the URL bar updates and each page is bookmarkable."
|
|
30
|
+
text "Try visiting /dashboard or /settings directly."
|
|
31
|
+
button "Go to Dashboard" do |s|
|
|
32
|
+
s[:page] = :dashboard
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
when :dashboard
|
|
36
|
+
header "Dashboard"
|
|
37
|
+
text "You navigated to /dashboard. Bookmark this URL and come back — it'll load right here."
|
|
38
|
+
text_field :dashboard_note, label: "Notes", placeholder: "Type something..."
|
|
39
|
+
button "Go to Settings" do |s|
|
|
40
|
+
s[:page] = :settings
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
when :settings
|
|
44
|
+
header "Settings"
|
|
45
|
+
text "You're at /settings. Press the browser Back button to go back."
|
|
46
|
+
checkbox :notifications, "Enable notifications"
|
|
47
|
+
checkbox :dark_mode, "Dark mode"
|
|
48
|
+
button "Back to Home" do |s|
|
|
49
|
+
s[:page] = :home
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end.run!
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Demonstrates the scroll_box component for constraining vertical space.
|
|
5
|
+
#
|
|
6
|
+
# Use cases shown:
|
|
7
|
+
# 1. Static long content - Terms & conditions, documentation
|
|
8
|
+
# 2. Live log output - Auto-scrolling log tail via SSE timers
|
|
9
|
+
# 3. Chat/message history - Scrollable message list
|
|
10
|
+
# 4. Data list - Long lists constrained to a fixed height
|
|
11
|
+
#
|
|
12
|
+
# Run with: bundle exec ruby examples/layout/scroll_box_demo.rb
|
|
13
|
+
|
|
14
|
+
require_relative "../../lib/stream_weaver"
|
|
15
|
+
|
|
16
|
+
# Simulated log messages for the live demo
|
|
17
|
+
LOG_MESSAGES = [
|
|
18
|
+
"INFO -- : Request GET /api/v2/users completed in 42ms",
|
|
19
|
+
"INFO -- : Cache HIT for key session:abc123",
|
|
20
|
+
"DEBUG -- : SQL (1.2ms) SELECT * FROM users WHERE active = true",
|
|
21
|
+
"INFO -- : Request POST /api/v2/orders completed in 118ms",
|
|
22
|
+
"WARN -- : Slow query detected (>100ms) on orders#index",
|
|
23
|
+
"INFO -- : Background job ProcessEmailJob enqueued",
|
|
24
|
+
"INFO -- : WebSocket connection opened for channel:dashboard",
|
|
25
|
+
"ERROR -- : Redis connection timeout after 5000ms, retrying...",
|
|
26
|
+
"INFO -- : Redis reconnected successfully",
|
|
27
|
+
"DEBUG -- : Cache MISS for key metrics:daily, computing...",
|
|
28
|
+
"INFO -- : Request GET /health returned 200 in 2ms",
|
|
29
|
+
"WARN -- : Rate limit approaching for IP 192.168.1.42 (85/100)",
|
|
30
|
+
"INFO -- : Deploy webhook received, version v2.14.3",
|
|
31
|
+
"INFO -- : Asset compilation completed in 3.2s",
|
|
32
|
+
"ERROR -- : Failed to send notification email: SMTP timeout",
|
|
33
|
+
].freeze
|
|
34
|
+
|
|
35
|
+
CHAT_MESSAGES = [
|
|
36
|
+
{ user: "Alice", text: "Has anyone seen the latency spike on the API gateway?" },
|
|
37
|
+
{ user: "Bob", text: "Yeah, I'm looking into it now. Seems like a connection pool issue." },
|
|
38
|
+
{ user: "Carol", text: "We saw something similar last week. Check the pgbouncer config." },
|
|
39
|
+
{ user: "Alice", text: "Good call. The max_client_conn was set too low." },
|
|
40
|
+
{ user: "Bob", text: "Bumped it to 200, deploying now." },
|
|
41
|
+
{ user: "Carol", text: "Keep an eye on memory usage after that change." },
|
|
42
|
+
{ user: "Bob", text: "Will do. Monitoring dashboard is up." },
|
|
43
|
+
{ user: "Alice", text: "Latency is back to normal. Nice work!" },
|
|
44
|
+
].freeze
|
|
45
|
+
|
|
46
|
+
TERMS = <<~TERMS
|
|
47
|
+
1. ACCEPTANCE OF TERMS. By accessing and using this service, you accept and agree to be bound by the terms and provision of this agreement.
|
|
48
|
+
|
|
49
|
+
2. PROVISION OF SERVICE. The service is provided "as is" and on an "as available" basis. We make no warranties, expressed or implied, and hereby disclaim all warranties including without limitation, implied warranties of merchantability and fitness for a particular purpose.
|
|
50
|
+
|
|
51
|
+
3. USER CONDUCT. You agree not to use the service for any unlawful purpose or in any way that could damage, disable, or impair the service. You agree not to attempt to gain unauthorized access to any part of the service.
|
|
52
|
+
|
|
53
|
+
4. INTELLECTUAL PROPERTY. All content included in the service, such as text, graphics, logos, and software, is the property of the service provider and is protected by copyright and other intellectual property laws.
|
|
54
|
+
|
|
55
|
+
5. PRIVACY POLICY. Your use of the service is also governed by our Privacy Policy, which is incorporated into these terms by reference. Please review our Privacy Policy to understand our practices.
|
|
56
|
+
|
|
57
|
+
6. LIMITATION OF LIABILITY. In no event shall the service provider be liable for any indirect, incidental, special, consequential, or punitive damages resulting from your use of the service.
|
|
58
|
+
|
|
59
|
+
7. MODIFICATIONS TO TERMS. We reserve the right to modify these terms at any time. Continued use of the service after changes constitutes acceptance of the new terms.
|
|
60
|
+
|
|
61
|
+
8. GOVERNING LAW. These terms shall be governed by and construed in accordance with the laws of the applicable jurisdiction, without regard to conflict of law provisions.
|
|
62
|
+
|
|
63
|
+
9. TERMINATION. We may terminate or suspend your access to the service at any time, without prior notice, for conduct that we believe violates these terms or is harmful to other users.
|
|
64
|
+
|
|
65
|
+
10. CONTACT. If you have questions about these terms, please contact us through the appropriate channels provided on our website.
|
|
66
|
+
TERMS
|
|
67
|
+
|
|
68
|
+
App = app "ScrollBox Demo", layout: :wide do
|
|
69
|
+
hstack(justify: :between, align: :center) do
|
|
70
|
+
header1 "ScrollBox Component Demo"
|
|
71
|
+
theme_switcher
|
|
72
|
+
end
|
|
73
|
+
md "The `scroll_box` constrains content to a fixed height with vertical scrolling."
|
|
74
|
+
|
|
75
|
+
columns widths: ["50%", "50%"] do
|
|
76
|
+
# ---- Left column ----
|
|
77
|
+
column do
|
|
78
|
+
# Use case 1: Static long content
|
|
79
|
+
header2 "Terms & Conditions"
|
|
80
|
+
text "A classic scroll_box use case - long legal text in a constrained area:"
|
|
81
|
+
|
|
82
|
+
scroll_box max_height: "200px" do
|
|
83
|
+
md TERMS
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Use case 2: Data list
|
|
87
|
+
header2 "File Browser"
|
|
88
|
+
text "Long lists constrained to avoid page bloat:"
|
|
89
|
+
|
|
90
|
+
scroll_box max_height: "250px" do
|
|
91
|
+
vstack spacing: :xs, divider: true do
|
|
92
|
+
50.times do |i|
|
|
93
|
+
ext = %w[.rb .js .yml .md .json].sample
|
|
94
|
+
size = rand(1..500)
|
|
95
|
+
hstack spacing: :sm, justify: :between, align: :center do
|
|
96
|
+
phrase "app/models/file_#{i + 1}#{ext}"
|
|
97
|
+
badge "#{size} KB", size: :sm
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# ---- Right column ----
|
|
105
|
+
column do
|
|
106
|
+
# Use case 3: Chat messages
|
|
107
|
+
header2 "Team Chat"
|
|
108
|
+
text "Message history in a scrollable container:"
|
|
109
|
+
|
|
110
|
+
scroll_box max_height: "200px" do
|
|
111
|
+
vstack spacing: :sm do
|
|
112
|
+
CHAT_MESSAGES.each do |msg|
|
|
113
|
+
div do
|
|
114
|
+
md "**#{msg[:user]}**: #{msg[:text]}"
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Use case 4: Live log output (SSE-updated)
|
|
121
|
+
header2 "Live Application Log"
|
|
122
|
+
text "Log entries arrive via SSE and accumulate in the scroll_box:"
|
|
123
|
+
|
|
124
|
+
scroll_box max_height: "250px" do
|
|
125
|
+
div id: "log-output" do
|
|
126
|
+
text "[#{Time.now.strftime('%H:%M:%S')}] Log stream started..."
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# --- Live log timer ---
|
|
133
|
+
every(2) do |streamer|
|
|
134
|
+
msg = LOG_MESSAGES.sample
|
|
135
|
+
timestamp = Time.now.strftime("%H:%M:%S.%L")
|
|
136
|
+
level_color = if msg.start_with?("ERROR")
|
|
137
|
+
"color: #ef4444"
|
|
138
|
+
elsif msg.start_with?("WARN")
|
|
139
|
+
"color: #eab308"
|
|
140
|
+
elsif msg.start_with?("DEBUG")
|
|
141
|
+
"color: #6b7280"
|
|
142
|
+
else
|
|
143
|
+
"color: #a3a3a3"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
streamer.append("#log-output") do
|
|
147
|
+
div style: "font-family: monospace; font-size: 0.85rem; padding: 2px 0; #{level_color}" do
|
|
148
|
+
text "[#{timestamp}] #{msg}"
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
App.run! if __FILE__ == $0
|