From 973caae7205f26022d40732b7246b387e1888f16 Mon Sep 17 00:00:00 2001 From: Jason Rogers Date: Tue, 10 Sep 2024 14:53:07 -0400 Subject: [PATCH] feat: starting work on experiments (sandbox) - new ExperimentsController - look for experiments in `Rails.root.join("tmp", "experiments")` - more work to come --- .../phlex_storybook/experiments_controller.rb | 46 +++++++++++++++++++ .../phlex_storybook/stories_controller.rb | 26 ----------- app/javascript/phlex_storybook/application.js | 6 +-- config/importmap.rb | 3 +- config/routes.rb | 5 ++ .../assets/phlex_storybook_application.css | 8 ++++ .../experiments/experiment_display.rb | 44 ++++++++++++++++++ .../components/experiments/index.rb | 28 +++++++++++ .../components/stories/component_display.rb | 2 - .../components/stories/component_selector.rb | 37 ++++++++++++++- lib/phlex_storybook/configuration.rb | 8 ++++ 11 files changed, 178 insertions(+), 35 deletions(-) create mode 100644 app/controllers/phlex_storybook/experiments_controller.rb create mode 100644 lib/phlex_storybook/components/experiments/experiment_display.rb create mode 100644 lib/phlex_storybook/components/experiments/index.rb diff --git a/app/controllers/phlex_storybook/experiments_controller.rb b/app/controllers/phlex_storybook/experiments_controller.rb new file mode 100644 index 0000000..5bedc44 --- /dev/null +++ b/app/controllers/phlex_storybook/experiments_controller.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module PhlexStorybook + class ExperimentsController < ApplicationController + before_action :reject_unless_editable! + + layout -> { Layouts::ApplicationLayout } + + def preview + respond_to do |format| + format.html { eval File.read(experiment) } + end + end + + def show + respond_to do |format| + format.html do + render Components::Experiments::Index.new(selected: experiment_name) + end + + format.turbo_stream do + render turbo_stream: [ + turbo_stream.replace( + "experiment_display", + Components::Experiments::ExperimentDisplay.new(name: experiment_name), + ), + ] + end + end + end + + private + + def experiment + PhlexStorybook.configuration.experiment experiment_name + end + + def experiment_name + params[:id] + end + + def reject_unless_editable! + redirect_to root_path unless PhlexStorybook.configuration.editable? + end + end +end diff --git a/app/controllers/phlex_storybook/stories_controller.rb b/app/controllers/phlex_storybook/stories_controller.rb index 680f571..e8c84a0 100644 --- a/app/controllers/phlex_storybook/stories_controller.rb +++ b/app/controllers/phlex_storybook/stories_controller.rb @@ -20,32 +20,6 @@ def show selected_story: story_id, ) end - - format.turbo_stream do - story_id = params[:story_id] - render turbo_stream: [ - turbo_stream.push_state(story_path(story_component, story_id: story_id)), - turbo_stream.replace( - "component_selector", - Components::Stories::ComponentSelector.new( - story_components: story_components, - selected: story_component, - selected_story: story_id - ), - ), - turbo_stream.replace( - "component_display", - Components::Stories::ComponentDisplay.new(story_component: story_component, story_id: story_id), - ), - turbo_stream.replace( - "component_properties", - Components::Stories::ComponentProperties.new( - story_component: story_component, - story_id: story_id, - ), - ), - ] - end end end diff --git a/app/javascript/phlex_storybook/application.js b/app/javascript/phlex_storybook/application.js index 6da88af..714a648 100644 --- a/app/javascript/phlex_storybook/application.js +++ b/app/javascript/phlex_storybook/application.js @@ -1,5 +1,5 @@ // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails -import { Turbo } from '@hotwired/turbo' +import "@hotwired/turbo-rails" import "controllers" -import TurboPower from 'turbo_power' -TurboPower.initialize(Turbo.StreamActions) +// import TurboPower from 'turbo_power' +// TurboPower.initialize(Turbo.StreamActions) diff --git a/config/importmap.rb b/config/importmap.rb index 9833ff6..366f670 100644 --- a/config/importmap.rb +++ b/config/importmap.rb @@ -1,8 +1,7 @@ pin "phlex_storybook", to: "phlex_storybook/application.js", preload: true -pin "@hotwired/turbo", to: "turbo.min.js", preload: true +pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true -pin "turbo_power", to: "https://ga.jspm.io/npm:turbo_power@0.1.6/dist/index.js" pin 'monaco-editor', to: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.51.0/+esm' pin_all_from PhlexStorybook::Engine.root.join("app/javascript/phlex_storybook/controllers"), under: "controllers", to: "phlex_storybook/controllers" diff --git a/config/routes.rb b/config/routes.rb index 05d0835..c0a0623 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,6 +2,11 @@ root to: 'stories#index' resources :components, only: [:update] + resources :experiments, only: [:show] do + member do + get :preview + end + end resources :stories, only: [:index, :show, :update] do collection do diff --git a/lib/phlex_storybook/assets/phlex_storybook_application.css b/lib/phlex_storybook/assets/phlex_storybook_application.css index f1bcf5b..4ad0642 100644 --- a/lib/phlex_storybook/assets/phlex_storybook_application.css +++ b/lib/phlex_storybook/assets/phlex_storybook_application.css @@ -907,6 +907,10 @@ fieldset{ display: block; } +.inline-block{ + display: inline-block; +} + .inline{ display: inline; } @@ -962,6 +966,10 @@ fieldset{ width: 25%; } +.w-3\/4{ + width: 75%; +} + .w-full{ width: 100%; } diff --git a/lib/phlex_storybook/components/experiments/experiment_display.rb b/lib/phlex_storybook/components/experiments/experiment_display.rb new file mode 100644 index 0000000..dbd491c --- /dev/null +++ b/lib/phlex_storybook/components/experiments/experiment_display.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module PhlexStorybook + module Components + module Experiments + class ExperimentDisplay < ApplicationView + # include Phlex::Rails::Helpers::IframeTag + + def initialize(name:) + @name = name + end + + def view_template + unless PhlexStorybook.configuration.experiment(@name) + turbo_frame_tag("experiment_display") do + blank_template + end + return + end + + turbo_frame_tag("experiment_display") do + div(class: "flex flex-col h-screen max-h-screen", data: { controller: "story-display copy" }) do + render_header @name + div(class: "px-2 flex-1 overflow-y-scroll overflow-x-hidden") do + iframe(src: helpers.preview_experiment_path(@name), class: "w-full h-full") + end + end + end + end + + private + + def blank_template + render_header("Select a component") + div(class: "px-2") { "Select an experiment from the left to see its preview" } + end + + def render_header(text) + h2(class: "bg-slate-900 text-white border-x border-slate-700 p-2 flex-none") { text } + end + end + end + end +end diff --git a/lib/phlex_storybook/components/experiments/index.rb b/lib/phlex_storybook/components/experiments/index.rb new file mode 100644 index 0000000..8650192 --- /dev/null +++ b/lib/phlex_storybook/components/experiments/index.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module PhlexStorybook + module Components + module Experiments + class Index < ApplicationView + def initialize(selected: nil) + @story_components = PhlexStorybook.configuration.components + @selected = selected + end + + def view_template + turbo_frame_tag("story_components") do + div class: "flex h-screen w-screen" do + div class: "flex-none w-1/4 min-w-40 max-w-80 bg-slate-700 text-white story-selector" do + render Stories::ComponentSelector.new(story_components: @story_components) + end + + div class: "flex-auto h-full w-3/4 bg-white" do + render ExperimentDisplay.new(name: @selected) + end + end + end + end + end + end + end +end diff --git a/lib/phlex_storybook/components/stories/component_display.rb b/lib/phlex_storybook/components/stories/component_display.rb index 31f262c..37c73e1 100644 --- a/lib/phlex_storybook/components/stories/component_display.rb +++ b/lib/phlex_storybook/components/stories/component_display.rb @@ -4,8 +4,6 @@ module PhlexStorybook module Components module Stories class ComponentDisplay < ApplicationView - include Phlex::Rails::Helpers::FieldSetTag - def initialize(story_component:, story_id: nil, **props) @story_component = story_component @story_id = story_id diff --git a/lib/phlex_storybook/components/stories/component_selector.rb b/lib/phlex_storybook/components/stories/component_selector.rb index e78b36b..8309f12 100644 --- a/lib/phlex_storybook/components/stories/component_selector.rb +++ b/lib/phlex_storybook/components/stories/component_selector.rb @@ -14,6 +14,8 @@ def view_template turbo_frame_tag("component_selector") do h2(class: "bg-slate-900 p-2") { "Components" } div(class: "px-2") do + render_experiments + @story_components_by_category.each do |category, story_components| h4 { category } ul do @@ -45,7 +47,7 @@ def active_selection def component_link(story_component) active = story_component == @selected a( - data: { turbo_stream: true }, + data: { turbo_frame: "_top" }, href: helpers.story_path(story_component.name), class: "#{active ? active_selection : ''}", ) do @@ -60,6 +62,37 @@ def icon_color(state) state ? 'stroke-sky-500' : 'stroke-slate-300' end + def render_experiments + a(data: { turbo_frame: "_top" }) do + h4(class: "inline-block") { "Experiments" } + end + + ul do + li do + a do + span(class: "pr-1") do + render Phlex::Icons::Lucide::FilePlus2.new(classes: "stroke-slate-300 size-4 inline") + end + span { "create new" } + end + end + PhlexStorybook.configuration.experiments.each do |experiment| + li do + name = File.basename(experiment, ".rb") + a( + href: helpers.experiment_path(name), + data: { turbo_frame: "_top" }, + ) do + span(class: "pr-1") do + render Phlex::Icons::Lucide::Codesandbox.new(classes: "stroke-slate-300 size-4 inline") + end + span { name.classify } + end + end + end + end + end + def story_link(story_component, title) id = story_component.id_for(title) active = id == @selected_story @@ -68,7 +101,7 @@ def story_link(story_component, title) a( class: "#{active ? active_selection : ''}", href: helpers.story_path(story_component, story_id: id), - data: { turbo_stream: true }, + data: { turbo_frame: "_top" }, ) do span(class: "pr-1") { render icon.new(classes: "#{icon_color(active)} size-4 inline") } span { "#{title}"} diff --git a/lib/phlex_storybook/configuration.rb b/lib/phlex_storybook/configuration.rb index ef0e34a..90789f0 100644 --- a/lib/phlex_storybook/configuration.rb +++ b/lib/phlex_storybook/configuration.rb @@ -12,6 +12,14 @@ def editable? Rails.env.development? end + def experiment(name) + experiments.detect { |e| e.end_with?("#{name}.rb") } + end + + def experiments + Dir[Rails.root.join("tmp", "experiments", "*.rb")] + end + def register(component, location) @components[component] = StoryComponent.new(component, location: location) end