Skip to content

Commit

Permalink
WIP: Back from the burn, where the hell was I...?
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicholas Barone committed Sep 12, 2024
1 parent a6a4f01 commit 4eea078
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 38 deletions.
35 changes: 19 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,36 @@ rails g storybook:install

Then, optionally:
```bash
rails g storybook:example
rails g storybook:examples
```

Restart your processes (stop and restart `./bin/dev`) and viola! Opens up a Storybook connected to your Rails server, and if you've also generated the example, will have a simple View Component showing up in Storybook.

## Usage

Today, write a JSON to describe your View Component's "story":
```
{
"title": "ExampleComponent",
"stories": [
{
"name": "default",
"parameters": {
"server": { "id": "example_component/default" }
}
}
]
}
Write a preview for your component, just like normal - but include the StoryBook::Preview module. You can also use the `PartialPreviewComponent` to render regular Rails partials as previews.
```ruby
class ExampleComponentPreview < ViewComponent::Preview
include Storybook::Preview
def default
render(ExampleComponent.new(title: "title"))
end

def default
render(PartialPreviewComponent.new(partial: "application/example"))
end
end
```
Note that the module will set the preview's layout to `storybook`, as there's steps to be done to make it look good (and work!) inside of Storybook.

Then run `rake storybook:stories` to generate the CSF JSON that Storybook uses to find your previews.

And... that's it! :D

Tomorrow(tm), run a rake task to generate those stories for you.

## Development

Inspired by [gem view_component-storybook](https://github.com/jonspalmer/view_component-storybook), but, I want to accomplish things in a different way (using the existing view component previews), to aim higher (handling view components, partials, *and* React components), and to aim specifically at integration with Chromatic.
Inspired by [gem view_component-storybook](https://github.com/jonspalmer/view_component-storybook), but, I want to accomplish things in a different way, to aim higher (handling ~~view components~~, ~~partials~~, *and* React components), and to aim specifically at integration with Chromatic.

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require "rails/generators"

class Storybook::ExampleGenerator < Rails::Generators::Base
class Storybook::ExamplesGenerator < Rails::Generators::Base
def install_view_components
insert_into_file "Gemfile", "gem 'view_component'"
system "bundle install"
Expand Down Expand Up @@ -28,7 +28,7 @@ def create_example_component_preview
# frozen_string_literal: true
class ExampleComponentPreview < ViewComponent::Preview
layout "storybook"
include Storybook::Preview
def default
render(ExampleComponent.new(title: "title"))
end
Expand All @@ -44,19 +44,23 @@ def with_content_block
RUBY
end

def create_example_story
create_file "stories/example_component.stories.json", <<~JSON
{
"title": "ExampleComponent",
"stories": [
{
"name": "default",
"parameters": {
"server": { "id": "example_component/default" }
}
}
]
}
JSON
def create_example_partial
create_file "app/views/application/_example.html.slim", <<~SLIM
span
= @title
SLIM
end

def create_example_partial_preview
# TODO: It goes here so the ViewComponent stuff can find it, but really should go elsewhere
create_file "test/components/previews/example_partial_preview.rb", <<~RUBY
# frozen_string_literal: true
class ExamplePartialPreview < ViewComponent::Preview
include Storybook::Preview
def default
render(Storybook::PartialPreviewComponent.new(partial: "application/example"))
end
end
RUBY
end
end
21 changes: 21 additions & 0 deletions lib/generators/storybook/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,25 @@ def update_storybook

# insert_into_file ".storybook/main.js", "@storybook/addon-controls", after: "addons: ["
end

def create_storybook_layout
# TODO: TailwindCSS / etc
create_file "app/views/layouts/storybook.html.slim", <<~SLIM
doctype html
html lang='en'
head
title Trainyard
meta charset="UTF-8"
meta[name="viewport" content="width=device-width,initial-scale=1"]
= csrf_meta_tags
= csp_meta_tag
= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload"
= stylesheet_link_tag "application"
= javascript_pack_tag "application"
body
div
main.ml-64.p-8
== yield
SLIM
end
end
1 change: 1 addition & 0 deletions lib/storybook.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require "storybook/version"
require "storybook/preview"
require "storybook/partial_preview_component"
require "storybook/react_preview_component"
require "storybook/railtie" if defined?(Rails::Railtie)

module Storybook; end
7 changes: 4 additions & 3 deletions lib/storybook/partial_preview_component.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
require 'view_component'
require "view_component"

module Storybook
class PartialPreviewComponent < ViewComponent::Base
slim_template <<~SLIM
= render partial: @partial
= render partial: @partial, locals: @locals
SLIM

def initialize(partial:)
def initialize(partial:, **locals)
@partial = partial
@locals = locals
end
end
end
17 changes: 15 additions & 2 deletions lib/storybook/preview.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,37 @@ module Storybook
module Preview
def self.included(base)
base.extend ClassMethods
base.layout "storybook"
end

module ClassMethods
def to_csf
{ title: component_name, stories: stories }
{ title: preview_name, stories: stories }
end

def stories
instance_methods(false).collect { |name| story(name) }
end

def story(name)
{ name:, parameters: { server: { id: "#{component_name&.underscore}/#{name}" } } }
{ name:, parameters: { server: { id: "#{preview_name.gsub("::", "/")}/#{name}" } } }
end

def preview_name
component_name || partial_name || react_name
end

def component_name
$1 if name =~ /(.+Component)(?=Preview)/
end

def partial_name
$1 if name =~ /(.+Partial)(?=Preview)/
end

def react_name
$1 if name =~ /(.+React)(?=Preview)/
end
end
end
end
17 changes: 17 additions & 0 deletions lib/storybook/react_preview_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require "view_component"
require "react_on_rails"

module Storybook
class ReactPreviewComponent < ViewComponent::Base
include ReactOnRails::Helper

slim_template <<~SLIM
= react_component @component, props: @props
SLIM

def initialize(component, **props)
@component = component
@props = props
end
end
end
2 changes: 1 addition & 1 deletion lib/storybook/tasks/stories.rake
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace :storybook do
Dir.glob("#{previews_dir}/**/*_preview.rb").each { |file| require file }

stories = ViewComponent::Preview.descendants.map do |preview|
[ preview.component_name&.underscore, preview.to_csf ] if preview < Storybook::Preview
[ preview.preview_name&.underscore, preview.to_csf ] if preview < Storybook::Preview
end

stories_dir = "stories"
Expand Down
1 change: 1 addition & 0 deletions rails-storybook.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Gem::Specification.new do |spec|

spec.add_dependency "rails", "~> 7.0"
spec.add_dependency "slim", "~> 5.2"
spec.add_dependency "react_on_rails", "~> 14.0"
spec.add_development_dependency "rails", "~> 7.0"

spec.add_development_dependency "bundler", "~> 2.5"
Expand Down

0 comments on commit 4eea078

Please sign in to comment.