lookbook 1.0.3 → 1.0.8
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/app/assets/lookbook/js/app.js +1 -0
- data/app/assets/lookbook/js/lib/socket.js +9 -5
- data/app/components/lookbook/base_component.rb +10 -2
- data/app/components/lookbook/copy_button/component.rb +1 -1
- data/app/components/lookbook/dimensions_display/component.rb +1 -4
- data/app/components/lookbook/embed/component.rb +1 -1
- data/app/components/lookbook/icon/component.rb +1 -5
- data/app/components/lookbook/nav/component.html.erb +1 -1
- data/app/components/lookbook/nav/item/component.rb +2 -2
- data/app/components/lookbook/params_editor/field/component.rb +1 -1
- data/app/components/lookbook/tabs/component.js +2 -2
- data/app/controllers/lookbook/application_controller.rb +10 -1
- data/app/controllers/lookbook/pages_controller.rb +0 -1
- data/app/controllers/lookbook/previews_controller.rb +9 -6
- data/app/helpers/lookbook/component_helper.rb +2 -1
- data/app/views/layouts/lookbook/application.html.erb +6 -36
- data/app/views/lookbook/index.html.erb +2 -2
- data/app/views/lookbook/previews/show.html.erb +1 -1
- data/config/routes.rb +1 -1
- data/lib/lookbook/config.rb +7 -3
- data/lib/lookbook/data.rb +2 -2
- data/lib/lookbook/engine.rb +34 -50
- data/lib/lookbook/parser.rb +19 -11
- data/lib/lookbook/preview.rb +22 -76
- data/lib/lookbook/preview_controller.rb +19 -1
- data/lib/lookbook/preview_example.rb +12 -5
- data/lib/lookbook/source_inspector.rb +2 -2
- data/lib/lookbook/store.rb +2 -2
- data/lib/lookbook/version.rb +1 -1
- data/lib/tasks/lookbook_tasks.rake +1 -2
- data/public/lookbook-assets/css/lookbook.css +8 -34
- data/public/lookbook-assets/css/lookbook.css.map +1 -1
- data/public/lookbook-assets/js/lookbook.js +174 -120
- data/public/lookbook-assets/js/lookbook.js.map +1 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 95694c758af19ee6a561b2aedfee93d932c663f7027471204da2dce393052a5a
         | 
| 4 | 
            +
              data.tar.gz: 1b4f3e4af714af47b6719cbbef7a861ad0ca2341089e2689ef8ed80b9a745867
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 0a148ae5b71546463c003244040e54de07106db6f927e61b77ff35c92d524f37ed59e53646833675a8d1c399968904ffe41891817e85628aa8da879af8aa3bd8
         | 
| 7 | 
            +
              data.tar.gz: ee91d909da4634558dbf542802ee770c921f0dfdec0bdc37592977b082a97705957bf7e19cf5168b599e78dca1f5d4222147417262c4b41f90b305a43c2c4f72
         | 
| @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            import { createConsumer } from "@rails/actioncable";
         | 
| 2 | 
            -
            import debounce from "debounce";
         | 
| 2 | 
            +
            import { debounce } from "throttle-debounce";
         | 
| 3 3 | 
             
            import { log } from "../plugins/logger";
         | 
| 4 4 |  | 
| 5 5 | 
             
            export default function socket(endpoint) {
         | 
| @@ -8,10 +8,14 @@ export default function socket(endpoint) { | |
| 8 8 | 
             
              return {
         | 
| 9 9 | 
             
                addListener(channel, callback) {
         | 
| 10 10 | 
             
                  consumer.subscriptions.create(channel, {
         | 
| 11 | 
            -
                    received: debounce( | 
| 12 | 
            -
                       | 
| 13 | 
            -
                       | 
| 14 | 
            -
             | 
| 11 | 
            +
                    received: debounce(
         | 
| 12 | 
            +
                      200,
         | 
| 13 | 
            +
                      (data) => {
         | 
| 14 | 
            +
                        log.debug("Lookbook files changed");
         | 
| 15 | 
            +
                        callback(data);
         | 
| 16 | 
            +
                      },
         | 
| 17 | 
            +
                      { atBegin: true }
         | 
| 18 | 
            +
                    ),
         | 
| 15 19 | 
             
                    connected() {
         | 
| 16 20 | 
             
                      log.info("Lookbook websocket connected");
         | 
| 17 21 | 
             
                    },
         | 
| @@ -31,11 +31,19 @@ module Lookbook | |
| 31 31 | 
             
                  nil
         | 
| 32 32 | 
             
                end
         | 
| 33 33 |  | 
| 34 | 
            +
                def alpine_encode(data)
         | 
| 35 | 
            +
                  if data.is_a? String
         | 
| 36 | 
            +
                    "\'#{json_escape data}\'"
         | 
| 37 | 
            +
                  else
         | 
| 38 | 
            +
                    json_escape data.to_json.tr("\"", "\'")
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 34 42 | 
             
                def prepare_alpine_data(x_data = nil)
         | 
| 35 43 | 
             
                  alpine_component_name = x_data || @html_attrs&.dig(:"x-data") || alpine_component
         | 
| 36 44 | 
             
                  if alpine_component_name.present?
         | 
| 37 | 
            -
                    args = Array.wrap(alpine_data)
         | 
| 38 | 
            -
                    args.any? ? "#{alpine_component_name}(#{ | 
| 45 | 
            +
                    args = Array.wrap(alpine_data).compact
         | 
| 46 | 
            +
                    args.any? ? "#{alpine_component_name}(#{args.join(",")})" : alpine_component_name
         | 
| 39 47 | 
             
                  end
         | 
| 40 48 | 
             
                end
         | 
| 41 49 | 
             
              end
         | 
| @@ -2,15 +2,12 @@ module Lookbook | |
| 2 2 | 
             
              class DimensionsDisplay::Component < Lookbook::BaseComponent
         | 
| 3 3 | 
             
                def initialize(target:, **html_attrs)
         | 
| 4 4 | 
             
                  @target = target
         | 
| 5 | 
            +
                  @alpine_data = alpine_encode(@target)
         | 
| 5 6 | 
             
                  super(**html_attrs)
         | 
| 6 7 | 
             
                end
         | 
| 7 8 |  | 
| 8 9 | 
             
                protected
         | 
| 9 10 |  | 
| 10 | 
            -
                def alpine_data
         | 
| 11 | 
            -
                  @target.to_json
         | 
| 12 | 
            -
                end
         | 
| 13 | 
            -
             | 
| 14 11 | 
             
                def alpine_component
         | 
| 15 12 | 
             
                  "dimensionsDisplayComponent"
         | 
| 16 13 | 
             
                end
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            module Lookbook
         | 
| 2 2 | 
             
              class Icon::Component < Lookbook::BaseComponent
         | 
| 3 3 | 
             
                def initialize(name:, size: 4, **html_attrs)
         | 
| 4 | 
            -
                  @ | 
| 4 | 
            +
                  @alpine_data = name.is_a?(Symbol) ? alpine_encode(name.to_s.tr("_", "-")) : name
         | 
| 5 5 | 
             
                  @size = size || 4
         | 
| 6 6 | 
             
                  super(**html_attrs)
         | 
| 7 7 | 
             
                end
         | 
| @@ -12,10 +12,6 @@ module Lookbook | |
| 12 12 |  | 
| 13 13 | 
             
                protected
         | 
| 14 14 |  | 
| 15 | 
            -
                def alpine_data
         | 
| 16 | 
            -
                  @icon_name
         | 
| 17 | 
            -
                end
         | 
| 18 | 
            -
             | 
| 19 15 | 
             
                def alpine_component
         | 
| 20 16 | 
             
                  "iconComponent"
         | 
| 21 17 | 
             
                end
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            import debounce from "debounce";
         | 
| 1 | 
            +
            import { debounce } from "throttle-debounce";
         | 
| 2 2 | 
             
            import tippy from "~/app/assets/lookbook/js/lib/tippy";
         | 
| 3 3 | 
             
            import { observeSize } from "@helpers/layout";
         | 
| 4 4 | 
             
            import { getElementSize } from "@helpers/dom";
         | 
| @@ -49,7 +49,7 @@ export default function tabsComponent(store) { | |
| 49 49 |  | 
| 50 50 | 
             
                    this.parentObserver = observeSize(
         | 
| 51 51 | 
             
                      this.$root.parentElement,
         | 
| 52 | 
            -
                      debounce(this.handleResize.bind(this) | 
| 52 | 
            +
                      debounce(10, this.handleResize.bind(this))
         | 
| 53 53 | 
             
                    );
         | 
| 54 54 |  | 
| 55 55 | 
             
                    this.$watch("visibleTabsCount", (value) => {
         | 
| @@ -1,6 +1,9 @@ | |
| 1 1 | 
             
            module Lookbook
         | 
| 2 2 | 
             
              class ApplicationController < ActionController::Base
         | 
| 3 | 
            -
                 | 
| 3 | 
            +
                if respond_to?(:content_security_policy)
         | 
| 4 | 
            +
                  content_security_policy false, if: -> { Rails.env.development? }
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 4 7 | 
             
                protect_from_forgery with: :exception
         | 
| 5 8 |  | 
| 6 9 | 
             
                helper Lookbook::ApplicationHelper
         | 
| @@ -8,6 +11,7 @@ module Lookbook | |
| 8 11 | 
             
                helper Lookbook::ComponentHelper
         | 
| 9 12 |  | 
| 10 13 | 
             
                before_action :generate_theme_overrides
         | 
| 14 | 
            +
                before_action :assign_collections
         | 
| 11 15 |  | 
| 12 16 | 
             
                def self.controller_path
         | 
| 13 17 | 
             
                  "lookbook"
         | 
| @@ -28,6 +32,11 @@ module Lookbook | |
| 28 32 | 
             
                  @theme_overrides ||= Lookbook.theme.to_css
         | 
| 29 33 | 
             
                end
         | 
| 30 34 |  | 
| 35 | 
            +
                def assign_collections
         | 
| 36 | 
            +
                  @previews = Preview.all
         | 
| 37 | 
            +
                  @pages = Page.all
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 31 40 | 
             
                def feature_enabled?(feature)
         | 
| 32 41 | 
             
                  Lookbook::Features.enabled?(feature)
         | 
| 33 42 | 
             
                end
         | 
| @@ -158,22 +158,25 @@ module Lookbook | |
| 158 158 |  | 
| 159 159 | 
             
                def panels
         | 
| 160 160 | 
             
                  return @panels if @panels.present?
         | 
| 161 | 
            -
                   | 
| 162 | 
            -
                   | 
| 161 | 
            +
                  inspector_data_hash = inspector_data.to_h
         | 
| 162 | 
            +
                  panel_counts = {}
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                  @panels = Lookbook.config.inspector_panels.map do |name, config|
         | 
| 163 165 | 
             
                    config_with_defaults = Lookbook.config.inspector_panel_defaults.merge(config)
         | 
| 166 | 
            +
                    panel_counts[config_with_defaults[:pane].to_sym] ||= 0
         | 
| 167 | 
            +
                    panel_counts[config_with_defaults[:pane].to_sym] += 1
         | 
| 164 168 |  | 
| 165 169 | 
             
                    callable_data = {
         | 
| 166 170 | 
             
                      name: name.to_s,
         | 
| 167 | 
            -
                      index_position:  | 
| 168 | 
            -
                      ** | 
| 171 | 
            +
                      index_position: panel_counts[config_with_defaults[:pane].to_sym],
         | 
| 172 | 
            +
                      **inspector_data_hash
         | 
| 169 173 | 
             
                    }
         | 
| 170 174 |  | 
| 171 175 | 
             
                    resolved_config = config_with_defaults.transform_values do |value|
         | 
| 172 176 | 
             
                      value.instance_of?(Proc) ? value.call(Lookbook::Store.new(callable_data)) : value
         | 
| 173 177 | 
             
                    end
         | 
| 174 178 | 
             
                    resolved_config[:name] = name.to_s
         | 
| 175 | 
            -
             | 
| 176 | 
            -
                    @panels << Lookbook::Store.new(resolved_config, deep: false)
         | 
| 179 | 
            +
                    Store.new(resolved_config)
         | 
| 177 180 | 
             
                  end
         | 
| 178 181 |  | 
| 179 182 | 
             
                  @panels = @panels.select(&:show).sort_by { |p| [p.position, p.label] }
         | 
| @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            <% content_for :shell do %>
         | 
| 2 | 
            -
              <% if  | 
| 2 | 
            +
              <% if @previews.any? || @pages.any? %>
         | 
| 3 3 | 
             
                <%= render_component :split_layout,
         | 
| 4 4 | 
             
                  alpine_data: "$store.layout.main",
         | 
| 5 5 | 
             
                  ":class": "$store.layout.mobile && '!block'" do |layout| %>
         | 
| @@ -14,14 +14,14 @@ | |
| 14 14 | 
             
                    cloak: true do %>
         | 
| 15 15 |  | 
| 16 16 | 
             
                    <%= render_component :split_layout,
         | 
| 17 | 
            -
                      alpine_data: "$store.layout.#{ | 
| 17 | 
            +
                      alpine_data: "$store.layout.#{@pages.any? && @previews.any? ? "sidebar" : "singleSectionSidebar"}",
         | 
| 18 18 | 
             
                      style: "height: calc(100vh - 2.5rem);" do |layout| %>
         | 
| 19 19 |  | 
| 20 | 
            -
                      <% if  | 
| 20 | 
            +
                      <% if @previews.any? %>
         | 
| 21 21 | 
             
                        <% layout.pane class: "overflow-hidden" do %>
         | 
| 22 22 | 
             
                          <%= render_component :nav,
         | 
| 23 23 | 
             
                            id: "previews-nav",
         | 
| 24 | 
            -
                            collection:  | 
| 24 | 
            +
                            collection: @previews,
         | 
| 25 25 | 
             
                            alpine_data: "$store.nav.previews",
         | 
| 26 26 | 
             
                            collapse_singles: true do |nav| %>
         | 
| 27 27 | 
             
                            <%= nav.toolbar do |toolbar| %>
         | 
| @@ -34,11 +34,11 @@ | |
| 34 34 | 
             
                        <% end %>
         | 
| 35 35 | 
             
                      <% end %>
         | 
| 36 36 |  | 
| 37 | 
            -
                      <% if  | 
| 37 | 
            +
                      <% if @pages.any? %>
         | 
| 38 38 | 
             
                        <% layout.pane class: "overflow-hidden" do %>
         | 
| 39 39 | 
             
                          <%= render_component :nav,
         | 
| 40 40 | 
             
                            id: "pages-nav",
         | 
| 41 | 
            -
                            collection:  | 
| 41 | 
            +
                            collection: @pages,
         | 
| 42 42 | 
             
                            alpine_data: "$store.nav.pages" do |nav| %>
         | 
| 43 43 | 
             
                            <%= nav.toolbar do |toolbar| %>
         | 
| 44 44 | 
             
                              <% toolbar.section padded: true do %>
         | 
| @@ -49,36 +49,6 @@ | |
| 49 49 | 
             
                        <% end %>
         | 
| 50 50 | 
             
                      <% end %>
         | 
| 51 51 | 
             
                    <% end %>
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                    <% if Lookbook::Preview.errors.any? %>
         | 
| 54 | 
            -
                      <div x-data="{hidden: false}" class="flex-none border-t border-lookbook-divider absolute bottom-0 left-0 right-0" x-show="!hidden">
         | 
| 55 | 
            -
                        <%= render_component :toolbar do |toolbar| %>
         | 
| 56 | 
            -
                          <% toolbar.section padded: true, class: "flex items-center" do %>
         | 
| 57 | 
            -
                            <%= icon  :alert_triangle, size: 4, class: "text-red-700" %>
         | 
| 58 | 
            -
                            <span class="ml-2">Preview load errors</span>
         | 
| 59 | 
            -
                          <% end %>
         | 
| 60 | 
            -
                          <% toolbar.section align: :right do %>
         | 
| 61 | 
            -
                            <% render_component :button, icon: :x, "@click": "hidden = !hidden" %>
         | 
| 62 | 
            -
                          <% end %>
         | 
| 63 | 
            -
                        <% end %>
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                        <div class="h-full max-h-[300px] overflow-hidden">
         | 
| 66 | 
            -
                          <div class="bg-red-50 w-full overflow-auto h-full">
         | 
| 67 | 
            -
                            <ul class="text-sm divide-y divide-red-200">
         | 
| 68 | 
            -
                              <% Lookbook::Preview.errors.each do |error| %>
         | 
| 69 | 
            -
                                <% error = error.is_a?(Lookbook::Error) ? error : Lookbook::Error.new(error) %>
         | 
| 70 | 
            -
                                <li class="px-4 py-3">
         | 
| 71 | 
            -
                                  <h4 class="break-all leading-tight text-xs ">
         | 
| 72 | 
            -
                                    <%= error.file_name %><%= ":#{error.line_number}" if error.line_number %>
         | 
| 73 | 
            -
                                  </h4>
         | 
| 74 | 
            -
                                  <pre class="text-red-800 text-xs mt-2 whitespace-pre-wrap opacity-80 font-mono"><%= error.message %></pre>
         | 
| 75 | 
            -
                                </li>
         | 
| 76 | 
            -
                              <% end %>
         | 
| 77 | 
            -
                            </ul>
         | 
| 78 | 
            -
                          </div>
         | 
| 79 | 
            -
                        </div>
         | 
| 80 | 
            -
                      </div>
         | 
| 81 | 
            -
                    <% end %>
         | 
| 82 52 | 
             
                  <% end %>
         | 
| 83 53 |  | 
| 84 54 | 
             
                  <% layout.pane id: "app-main", class: "overflow-hidden h-full", ":class": "$store.layout.mobile && 'w-screen'" do %>
         | 
| @@ -1,10 +1,10 @@ | |
| 1 1 | 
             
            <div id="landing" class="flex flex-col items-center justify-center h-full w-full">
         | 
| 2 | 
            -
              <div class="text-center" id="landing-<%=  | 
| 2 | 
            +
              <div class="text-center" id="landing-<%= @previews.any? ? "with" : "no" %>-content">
         | 
| 3 3 | 
             
                <h5 class="text-base text-lookbook-blank-slate-title truncate uppercase font-black tracking-wider mb-2">
         | 
| 4 4 | 
             
                  <%= config.project_name %>
         | 
| 5 5 | 
             
                </h5>
         | 
| 6 6 | 
             
                <div class="opacity-60">
         | 
| 7 | 
            -
                  <% if  | 
| 7 | 
            +
                  <% if @previews.any? %>
         | 
| 8 8 | 
             
                    <p>Select a preview from the nav to get started.</p>
         | 
| 9 9 | 
             
                  <% else %>
         | 
| 10 10 | 
             
                    <p><a class="underline" href="https://lookbook.build/guide/previews" target="_blank">Create a preview</a> to get started.</p>
         | 
| @@ -25,7 +25,7 @@ | |
| 25 25 |  | 
| 26 26 | 
             
                  <% toolbar.section divide: :left, class: "flex-none relative z-10" do %>
         | 
| 27 27 | 
             
                    <%= render_component :button_group do |group| %>
         | 
| 28 | 
            -
                      <% if  | 
| 28 | 
            +
                      <% if @pages.any? %>
         | 
| 29 29 | 
             
                        <% group.button icon: :code,
         | 
| 30 30 | 
             
                          tooltip: "Copy page embed code",
         | 
| 31 31 | 
             
                          copy: true do %>
         | 
    
        data/config/routes.rb
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            Lookbook::Engine.routes.draw do
         | 
| 2 2 | 
             
              if Lookbook::Engine.websocket?
         | 
| 3 | 
            -
                mount Lookbook::Engine.websocket => Lookbook.config.cable_mount_path
         | 
| 3 | 
            +
                mount Lookbook::Engine.websocket => Lookbook.config.cable_mount_path, :as => :cable
         | 
| 4 4 | 
             
              end
         | 
| 5 5 |  | 
| 6 6 | 
             
              root to: "application#index", as: :lookbook_home
         | 
    
        data/lib/lookbook/config.rb
    CHANGED
    
    | @@ -5,7 +5,7 @@ require "lookbook/store" | |
| 5 5 | 
             
            module Lookbook
         | 
| 6 6 | 
             
              class Config
         | 
| 7 7 | 
             
                def initialize
         | 
| 8 | 
            -
                  @options = Store.new
         | 
| 8 | 
            +
                  @options = Store.new({}, true)
         | 
| 9 9 |  | 
| 10 10 | 
             
                  @options.set({
         | 
| 11 11 | 
             
                    project_name: "Lookbook",
         | 
| @@ -24,6 +24,7 @@ module Lookbook | |
| 24 24 | 
             
                    preview_display_params: {},
         | 
| 25 25 | 
             
                    preview_srcdoc: nil,
         | 
| 26 26 | 
             
                    preview_tags: {},
         | 
| 27 | 
            +
                    preview_disable_action_view_annotations: true,
         | 
| 27 28 | 
             
                    sort_examples: false,
         | 
| 28 29 |  | 
| 29 30 | 
             
                    listen: Rails.env.development?,
         | 
| @@ -31,10 +32,9 @@ module Lookbook | |
| 31 32 | 
             
                    listen_extensions: ["rb", "html.*"],
         | 
| 32 33 | 
             
                    listen_use_polling: false,
         | 
| 33 34 |  | 
| 34 | 
            -
                    cable_mount_path: "/ | 
| 35 | 
            +
                    cable_mount_path: "/cable",
         | 
| 35 36 | 
             
                    cable_logger: Lookbook.logger,
         | 
| 36 37 |  | 
| 37 | 
            -
                    runtime_parsing: !Rails.env.production?,
         | 
| 38 38 | 
             
                    parser_registry_path: "tmp/storage/.yardoc",
         | 
| 39 39 |  | 
| 40 40 | 
             
                    ui_theme: "indigo",
         | 
| @@ -104,6 +104,10 @@ module Lookbook | |
| 104 104 | 
             
                  })
         | 
| 105 105 | 
             
                end
         | 
| 106 106 |  | 
| 107 | 
            +
                def runtime_parsing=(value)
         | 
| 108 | 
            +
                  Lookbook.logger.warn "The `runtime_parsing` config option has been deprecated and will be removed in v2.0"
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
             | 
| 107 111 | 
             
                def project_name
         | 
| 108 112 | 
             
                  @options.project_name == false ? nil : @options.project_name
         | 
| 109 113 | 
             
                end
         | 
    
        data/lib/lookbook/data.rb
    CHANGED
    
    
    
        data/lib/lookbook/engine.rb
    CHANGED
    
    | @@ -35,7 +35,7 @@ module Lookbook | |
| 35 35 | 
             
                  {
         | 
| 36 36 | 
             
                    version: version,
         | 
| 37 37 | 
             
                    env: Rails.env.to_s,
         | 
| 38 | 
            -
                    config: config
         | 
| 38 | 
            +
                    config: config.to_h
         | 
| 39 39 | 
             
                  }
         | 
| 40 40 | 
             
                end
         | 
| 41 41 |  | 
| @@ -43,18 +43,10 @@ module Lookbook | |
| 43 43 | 
             
                  Preview.all
         | 
| 44 44 | 
             
                end
         | 
| 45 45 |  | 
| 46 | 
            -
                def previews?
         | 
| 47 | 
            -
                  Preview.any?
         | 
| 48 | 
            -
                end
         | 
| 49 | 
            -
             | 
| 50 46 | 
             
                def pages
         | 
| 51 47 | 
             
                  Page.all
         | 
| 52 48 | 
             
                end
         | 
| 53 49 |  | 
| 54 | 
            -
                def pages?
         | 
| 55 | 
            -
                  Page.any?
         | 
| 56 | 
            -
                end
         | 
| 57 | 
            -
             | 
| 58 50 | 
             
                def broadcast(event_name, data = {})
         | 
| 59 51 | 
             
                  Engine.websocket&.broadcast(event_name.to_s, data)
         | 
| 60 52 | 
             
                end
         | 
| @@ -99,6 +91,11 @@ module Lookbook | |
| 99 91 | 
             
                  @preview_controller = Lookbook.config.preview_controller.constantize
         | 
| 100 92 | 
             
                  @preview_controller.include(Lookbook::PreviewController)
         | 
| 101 93 |  | 
| 94 | 
            +
                  parser.after_parse do |registry|
         | 
| 95 | 
            +
                    Preview.load!(registry.all(:class))
         | 
| 96 | 
            +
                    reload_ui
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
             | 
| 102 99 | 
             
                  if Gem::Version.new(Rails.version) >= Gem::Version.new("6.1.3.1")
         | 
| 103 100 | 
             
                    # Rails.application.server is only available for newer Rails versions
         | 
| 104 101 | 
             
                    Rails.application.server do
         | 
| @@ -111,19 +108,9 @@ module Lookbook | |
| 111 108 | 
             
                    end
         | 
| 112 109 | 
             
                  end
         | 
| 113 110 |  | 
| 114 | 
            -
                   | 
| 115 | 
            -
                    Lookbook::Engine. | 
| 116 | 
            -
                  else
         | 
| 117 | 
            -
                    unless File.exist?(config.lookbook.parser_registry_path)
         | 
| 118 | 
            -
                      Lookbook.logger.warn "
         | 
| 119 | 
            -
                        Runtime parsing is disabled but no registry file has been found.
         | 
| 120 | 
            -
                        Did you run `rake lookbook:preparse` before starting the app?
         | 
| 121 | 
            -
                        Expected to find registry file at #{config.lookbook.parser_registry_path}
         | 
| 122 | 
            -
                      "
         | 
| 123 | 
            -
                    end
         | 
| 111 | 
            +
                  parser.parse do
         | 
| 112 | 
            +
                    Lookbook::Engine.run_hooks(:after_initialize)
         | 
| 124 113 | 
             
                  end
         | 
| 125 | 
            -
             | 
| 126 | 
            -
                  Lookbook::Engine.run_hooks(:after_initialize)
         | 
| 127 114 | 
             
                end
         | 
| 128 115 |  | 
| 129 116 | 
             
                at_exit do
         | 
| @@ -140,43 +127,40 @@ module Lookbook | |
| 140 127 | 
             
                    return unless config.listen == true
         | 
| 141 128 | 
             
                    Listen.logger = Lookbook.logger
         | 
| 142 129 |  | 
| 143 | 
            -
                     | 
| 144 | 
            -
             | 
| 145 | 
            -
                       | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
             | 
| 149 | 
            -
             | 
| 150 | 
            -
                         | 
| 151 | 
            -
                      rescue
         | 
| 130 | 
            +
                    listen_paths = config.listen_paths.uniq
         | 
| 131 | 
            +
                    if listen_paths.any?
         | 
| 132 | 
            +
                      preview_listener = Listen.to(*listen_paths,
         | 
| 133 | 
            +
                        only: /\.(#{config.listen_extensions.join("|")})$/,
         | 
| 134 | 
            +
                        force_polling: config.listen_use_polling) do |modified, added, removed|
         | 
| 135 | 
            +
                        parser.parse do
         | 
| 136 | 
            +
                          run_hooks(:after_change, {modified: modified, added: added, removed: removed})
         | 
| 137 | 
            +
                        end
         | 
| 152 138 | 
             
                      end
         | 
| 153 | 
            -
                       | 
| 154 | 
            -
                      reload_ui(changes)
         | 
| 155 | 
            -
                      run_hooks(:after_change, changes)
         | 
| 139 | 
            +
                      register_listener(preview_listener)
         | 
| 156 140 | 
             
                    end
         | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
                     | 
| 160 | 
            -
                      * | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
                       | 
| 141 | 
            +
             | 
| 142 | 
            +
                    page_paths = config.page_paths.uniq
         | 
| 143 | 
            +
                    if page_paths.any?
         | 
| 144 | 
            +
                      page_listener = Listen.to(*page_paths,
         | 
| 145 | 
            +
                        only: /\.(html.*|md.*)$/,
         | 
| 146 | 
            +
                        force_polling: config.listen_use_polling) do |modified, added, removed|
         | 
| 147 | 
            +
                        changes = {modified: modified, added: added, removed: removed}
         | 
| 148 | 
            +
                        reload_ui
         | 
| 149 | 
            +
                        run_hooks(:after_change, changes)
         | 
| 150 | 
            +
                      end
         | 
| 151 | 
            +
                      register_listener(page_listener)
         | 
| 167 152 | 
             
                    end
         | 
| 168 | 
            -
                    register_listener(page_listener)
         | 
| 169 153 | 
             
                  end
         | 
| 170 154 |  | 
| 171 155 | 
             
                  def websocket
         | 
| 172 156 | 
             
                    config = Lookbook.config
         | 
| 173 157 | 
             
                    return @websocket unless @websocket.nil?
         | 
| 174 | 
            -
                    return unless config.auto_refresh == true
         | 
| 158 | 
            +
                    return unless config.auto_refresh == true && config.listen == true && !Rails.env.test?
         | 
| 175 159 | 
             
                    Lookbook.logger.info "Initializing websocket"
         | 
| 176 160 |  | 
| 177 161 | 
             
                    cable = ActionCable::Server::Configuration.new
         | 
| 178 162 | 
             
                    cable.cable = {adapter: "async"}.with_indifferent_access
         | 
| 179 | 
            -
                    cable.mount_path =  | 
| 163 | 
            +
                    cable.mount_path = nil
         | 
| 180 164 | 
             
                    cable.connection_class = -> { Lookbook::Connection }
         | 
| 181 165 | 
             
                    cable.logger = config.cable_logger
         | 
| 182 166 |  | 
| @@ -190,7 +174,7 @@ module Lookbook | |
| 190 174 | 
             
                  end
         | 
| 191 175 |  | 
| 192 176 | 
             
                  def websocket_mount_path
         | 
| 193 | 
            -
                    "#{mounted_path}#{config.lookbook.cable_mount_path}" if websocket?
         | 
| 177 | 
            +
                    "#{mounted_path}#{config.lookbook.cable_mount_path}".gsub("//", "/") if websocket?
         | 
| 194 178 | 
             
                  end
         | 
| 195 179 |  | 
| 196 180 | 
             
                  def websocket?
         | 
| @@ -202,7 +186,7 @@ module Lookbook | |
| 202 186 | 
             
                  end
         | 
| 203 187 |  | 
| 204 188 | 
             
                  def parser
         | 
| 205 | 
            -
                    @parser ||= Lookbook::Parser.new(config.lookbook.preview_paths | 
| 189 | 
            +
                    @parser ||= Lookbook::Parser.new(config.lookbook.preview_paths)
         | 
| 206 190 | 
             
                  end
         | 
| 207 191 |  | 
| 208 192 | 
             
                  def log_level
         | 
| @@ -237,8 +221,8 @@ module Lookbook | |
| 237 221 | 
             
                    end
         | 
| 238 222 | 
             
                  end
         | 
| 239 223 |  | 
| 240 | 
            -
                  def reload_ui | 
| 241 | 
            -
                    websocket&.broadcast("reload",  | 
| 224 | 
            +
                  def reload_ui
         | 
| 225 | 
            +
                    websocket&.broadcast("reload", {})
         | 
| 242 226 | 
             
                  end
         | 
| 243 227 |  | 
| 244 228 | 
             
                  def prevent_listening?
         | 
    
        data/lib/lookbook/parser.rb
    CHANGED
    
    | @@ -3,24 +3,32 @@ require "yard" | |
| 3 3 | 
             
            module Lookbook
         | 
| 4 4 | 
             
              class Parser
         | 
| 5 5 | 
             
                attr_reader :registry_path
         | 
| 6 | 
            -
                def initialize(paths | 
| 6 | 
            +
                def initialize(paths)
         | 
| 7 7 | 
             
                  @paths = paths.map { |p| "#{p}/**/*preview.rb" }
         | 
| 8 | 
            -
                  @ | 
| 9 | 
            -
                   | 
| 8 | 
            +
                  @after_parse_callbacks = []
         | 
| 9 | 
            +
                  @after_parse_once_callbacks = []
         | 
| 10 | 
            +
                  @parsing = false
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  YARD::Parser::SourceParser.after_parse_list do
         | 
| 13 | 
            +
                    [*@after_parse_callbacks, *@after_parse_once_callbacks].each do |callback|
         | 
| 14 | 
            +
                      callback.call(YARD::Registry)
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                    @after_parse_once_callbacks = []
         | 
| 17 | 
            +
                    @parsing = false
         | 
| 18 | 
            +
                  end
         | 
| 10 19 | 
             
                end
         | 
| 11 20 |  | 
| 12 | 
            -
                def parse
         | 
| 13 | 
            -
                   | 
| 14 | 
            -
             | 
| 21 | 
            +
                def parse(&block)
         | 
| 22 | 
            +
                  unless @parsing
         | 
| 23 | 
            +
                    @parsing = true
         | 
| 24 | 
            +
                    @after_parse_once_callbacks << block if block
         | 
| 25 | 
            +
                    YARD::Registry.clear
         | 
| 15 26 | 
             
                    YARD.parse(@paths)
         | 
| 16 | 
            -
                    YARD::Registry.save(false, registry_path)
         | 
| 17 27 | 
             
                  end
         | 
| 18 28 | 
             
                end
         | 
| 19 29 |  | 
| 20 | 
            -
                def  | 
| 21 | 
            -
                   | 
| 22 | 
            -
                  registry.load!(registry_path)
         | 
| 23 | 
            -
                  registry.get(path)
         | 
| 30 | 
            +
                def after_parse(&block)
         | 
| 31 | 
            +
                  @after_parse_callbacks << block
         | 
| 24 32 | 
             
                end
         | 
| 25 33 |  | 
| 26 34 | 
             
                class << self
         |