showcase-rails 0.2.1 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -1
- data/app/assets/builds/showcase.css +81 -36
- data/app/models/showcase/path.rb +8 -16
- data/app/models/showcase/sample.rb +8 -2
- data/app/views/layouts/showcase.html.erb +2 -2
- data/app/views/showcase/engine/_preview.html.erb +3 -1
- data/app/views/showcase/engine/_sample.html.erb +10 -1
- data/lib/showcase/options.rb +89 -0
- data/lib/showcase/version.rb +1 -1
- data/lib/showcase.rb +33 -0
- data/lib/tasks/showcase_tasks.rake +3 -14
- metadata +4 -5
- data/app/controllers/showcase/pages_controller.rb +0 -5
- data/app/models/showcase/options.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '081d707dee9578e786c17cb621826f685bf2a4f9eab5221037b2394ac3b6805b'
|
4
|
+
data.tar.gz: 46fad2bf9b84aba2bf22bf0a627eb225ee904cd67da55cda4c0690b34d8d5a07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 480d2d5a3c891703603caec5131d3990e19d31c97e815c622d8c6152ec2c1519a430e55416fc63caab1d7f136dd0fe96bf9e45a39bbf854e39134339822f6157
|
7
|
+
data.tar.gz: d35a92bd276b05225cdb827a9d3ec832665e1b0978b2ec02294ecc3d0810fee926fbb5f58d989612177ebe879d833ea8a476057efa04ca845d5e3e2b1808694a
|
data/README.md
CHANGED
@@ -29,7 +29,32 @@ Which will then render the following:
|
|
29
29
|
|
30
30
|
![](/readme/example.png?raw=true "Showcase showing a button component")
|
31
31
|
|
32
|
-
##
|
32
|
+
## Using options contexts
|
33
|
+
|
34
|
+
Showcase also supports custom options contexts. They're useful for cases where the options have a very specific format and it would be nice to keep them standardized.
|
35
|
+
|
36
|
+
By default, Showcase ships Nice Partials and Stimulus contexts out of the box. Here's a sample of the Stimulus one:
|
37
|
+
|
38
|
+
```erb
|
39
|
+
<% showcase.options.stimulus controller: :welcome do |o| %>
|
40
|
+
<% o.optional.targets :greeter, "If the id of the target element must be printed" %>
|
41
|
+
<% end %>
|
42
|
+
```
|
43
|
+
|
44
|
+
In case Showcase didn't ship with a Stimulus context, here's how you could add it:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
# config/initializers/showcase.rb
|
48
|
+
if defined?(Showcase)
|
49
|
+
Showcase.options.define :stimulus do
|
50
|
+
def targets(name, ...)
|
51
|
+
option(%(data-#{@controller}-target="#{name}"), ...)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
## Automatic integration testing
|
33
58
|
|
34
59
|
Showcase automatically runs integration tests for all your Showcases by rendering them and asserting they respond with `200 OK`. As long as `gem "showcase-rails"` is in the `:test` group you're set.
|
35
60
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
! tailwindcss v3.2.
|
2
|
+
! tailwindcss v3.2.7 | MIT License | https://tailwindcss.com
|
3
3
|
*/
|
4
4
|
|
5
5
|
/*
|
@@ -691,6 +691,10 @@ select {
|
|
691
691
|
grid-column: span 9 / span 9;
|
692
692
|
}
|
693
693
|
|
694
|
+
.sc-m-2 {
|
695
|
+
margin: 0.5rem;
|
696
|
+
}
|
697
|
+
|
694
698
|
.sc-mb-2 {
|
695
699
|
margin-bottom: 0.5rem;
|
696
700
|
}
|
@@ -699,6 +703,10 @@ select {
|
|
699
703
|
margin-bottom: 1rem;
|
700
704
|
}
|
701
705
|
|
706
|
+
.sc-mt-1 {
|
707
|
+
margin-top: 0.25rem;
|
708
|
+
}
|
709
|
+
|
702
710
|
.sc-inline-block {
|
703
711
|
display: inline-block;
|
704
712
|
}
|
@@ -765,10 +773,13 @@ select {
|
|
765
773
|
align-items: center;
|
766
774
|
}
|
767
775
|
|
768
|
-
.sc-
|
769
|
-
|
770
|
-
|
771
|
-
|
776
|
+
.sc-justify-between {
|
777
|
+
justify-content: space-between;
|
778
|
+
}
|
779
|
+
|
780
|
+
.sc-gap-x-2 {
|
781
|
+
-moz-column-gap: 0.5rem;
|
782
|
+
column-gap: 0.5rem;
|
772
783
|
}
|
773
784
|
|
774
785
|
.sc-space-x-2 > :not([hidden]) ~ :not([hidden]) {
|
@@ -783,6 +794,12 @@ select {
|
|
783
794
|
margin-bottom: calc(1rem * var(--tw-space-y-reverse));
|
784
795
|
}
|
785
796
|
|
797
|
+
.sc-space-y-8 > :not([hidden]) ~ :not([hidden]) {
|
798
|
+
--tw-space-y-reverse: 0;
|
799
|
+
margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));
|
800
|
+
margin-bottom: calc(2rem * var(--tw-space-y-reverse));
|
801
|
+
}
|
802
|
+
|
786
803
|
.sc-overflow-scroll {
|
787
804
|
overflow: scroll;
|
788
805
|
}
|
@@ -801,6 +818,10 @@ select {
|
|
801
818
|
white-space: nowrap;
|
802
819
|
}
|
803
820
|
|
821
|
+
.sc-rounded-full {
|
822
|
+
border-radius: 9999px;
|
823
|
+
}
|
824
|
+
|
804
825
|
.sc-rounded-md {
|
805
826
|
border-radius: 0.375rem;
|
806
827
|
}
|
@@ -813,16 +834,20 @@ select {
|
|
813
834
|
border-width: 0px;
|
814
835
|
}
|
815
836
|
|
816
|
-
.sc-border-
|
817
|
-
border-
|
837
|
+
.sc-border-2 {
|
838
|
+
border-width: 2px;
|
839
|
+
}
|
840
|
+
|
841
|
+
.sc-border-b {
|
842
|
+
border-bottom-width: 1px;
|
818
843
|
}
|
819
844
|
|
820
845
|
.sc-border-r {
|
821
846
|
border-right-width: 1px;
|
822
847
|
}
|
823
848
|
|
824
|
-
.sc-border-
|
825
|
-
border-
|
849
|
+
.sc-border-t {
|
850
|
+
border-top-width: 1px;
|
826
851
|
}
|
827
852
|
|
828
853
|
.sc-border-gray-200 {
|
@@ -830,26 +855,36 @@ select {
|
|
830
855
|
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
831
856
|
}
|
832
857
|
|
833
|
-
.sc-
|
858
|
+
.sc-border-indigo-300 {
|
859
|
+
--tw-border-opacity: 1;
|
860
|
+
border-color: rgb(165 180 252 / var(--tw-border-opacity));
|
861
|
+
}
|
862
|
+
|
863
|
+
.sc-bg-indigo-50 {
|
834
864
|
--tw-bg-opacity: 1;
|
835
|
-
background-color: rgb(
|
865
|
+
background-color: rgb(238 242 255 / var(--tw-bg-opacity));
|
836
866
|
}
|
837
867
|
|
838
868
|
.sc-bg-slate-100\/50 {
|
839
869
|
background-color: rgb(241 245 249 / 0.5);
|
840
870
|
}
|
841
871
|
|
842
|
-
.sc-bg-
|
872
|
+
.sc-bg-slate-50 {
|
843
873
|
--tw-bg-opacity: 1;
|
844
|
-
background-color: rgb(
|
874
|
+
background-color: rgb(248 250 252 / var(--tw-bg-opacity));
|
875
|
+
}
|
876
|
+
|
877
|
+
.sc-p-12 {
|
878
|
+
padding: 3rem;
|
845
879
|
}
|
846
880
|
|
847
881
|
.sc-p-4 {
|
848
882
|
padding: 1rem;
|
849
883
|
}
|
850
884
|
|
851
|
-
.sc-
|
852
|
-
padding:
|
885
|
+
.sc-px-2 {
|
886
|
+
padding-left: 0.5rem;
|
887
|
+
padding-right: 0.5rem;
|
853
888
|
}
|
854
889
|
|
855
890
|
.sc-px-4 {
|
@@ -857,6 +892,11 @@ select {
|
|
857
892
|
padding-right: 1rem;
|
858
893
|
}
|
859
894
|
|
895
|
+
.sc-px-8 {
|
896
|
+
padding-left: 2rem;
|
897
|
+
padding-right: 2rem;
|
898
|
+
}
|
899
|
+
|
860
900
|
.sc-py-2 {
|
861
901
|
padding-top: 0.5rem;
|
862
902
|
padding-bottom: 0.5rem;
|
@@ -867,11 +907,6 @@ select {
|
|
867
907
|
padding-bottom: 1.25rem;
|
868
908
|
}
|
869
909
|
|
870
|
-
.sc-px-8 {
|
871
|
-
padding-left: 2rem;
|
872
|
-
padding-right: 2rem;
|
873
|
-
}
|
874
|
-
|
875
910
|
.sc-pl-4 {
|
876
911
|
padding-left: 1rem;
|
877
912
|
}
|
@@ -880,9 +915,9 @@ select {
|
|
880
915
|
padding-top: 1.75rem;
|
881
916
|
}
|
882
917
|
|
883
|
-
.sc-text-
|
884
|
-
font-size: 1.
|
885
|
-
line-height:
|
918
|
+
.sc-text-2xl {
|
919
|
+
font-size: 1.5rem;
|
920
|
+
line-height: 2rem;
|
886
921
|
}
|
887
922
|
|
888
923
|
.sc-text-3xl {
|
@@ -895,17 +930,14 @@ select {
|
|
895
930
|
line-height: 1.5rem;
|
896
931
|
}
|
897
932
|
|
898
|
-
.sc-text-
|
899
|
-
font-size: 1.
|
900
|
-
line-height:
|
901
|
-
}
|
902
|
-
|
903
|
-
.sc-font-semibold {
|
904
|
-
font-weight: 600;
|
933
|
+
.sc-text-xl {
|
934
|
+
font-size: 1.25rem;
|
935
|
+
line-height: 1.75rem;
|
905
936
|
}
|
906
937
|
|
907
|
-
.sc-
|
908
|
-
font-
|
938
|
+
.sc-text-xs {
|
939
|
+
font-size: 0.75rem;
|
940
|
+
line-height: 1rem;
|
909
941
|
}
|
910
942
|
|
911
943
|
.sc-font-black {
|
@@ -916,6 +948,14 @@ select {
|
|
916
948
|
font-weight: 500;
|
917
949
|
}
|
918
950
|
|
951
|
+
.sc-font-normal {
|
952
|
+
font-weight: 400;
|
953
|
+
}
|
954
|
+
|
955
|
+
.sc-font-semibold {
|
956
|
+
font-weight: 600;
|
957
|
+
}
|
958
|
+
|
919
959
|
.sc-italic {
|
920
960
|
font-style: italic;
|
921
961
|
}
|
@@ -929,6 +969,11 @@ select {
|
|
929
969
|
color: rgb(0 0 0 / var(--tw-text-opacity));
|
930
970
|
}
|
931
971
|
|
972
|
+
.sc-text-slate-500 {
|
973
|
+
--tw-text-opacity: 1;
|
974
|
+
color: rgb(100 116 139 / var(--tw-text-opacity));
|
975
|
+
}
|
976
|
+
|
932
977
|
.hover\:sc-select-all:hover {
|
933
978
|
-webkit-user-select: all;
|
934
979
|
-moz-user-select: all;
|
@@ -948,11 +993,11 @@ select {
|
|
948
993
|
}
|
949
994
|
|
950
995
|
@media (min-width: 1280px) {
|
951
|
-
.xl\:sc-col-span-2 {
|
952
|
-
grid-column: span 2 / span 2;
|
953
|
-
}
|
954
|
-
|
955
996
|
.xl\:sc-col-span-10 {
|
956
997
|
grid-column: span 10 / span 10;
|
957
998
|
}
|
999
|
+
|
1000
|
+
.xl\:sc-col-span-2 {
|
1001
|
+
grid-column: span 2 / span 2;
|
1002
|
+
}
|
958
1003
|
}
|
data/app/models/showcase/path.rb
CHANGED
@@ -1,19 +1,16 @@
|
|
1
1
|
class Showcase::Path
|
2
|
-
class Tree < Struct.new(:id, :children)
|
2
|
+
class Tree < Struct.new(:id, :children, :root)
|
3
3
|
def initialize(id, children = [])
|
4
|
-
super
|
4
|
+
super(id, children, false)
|
5
5
|
end
|
6
|
+
alias_method :root?, :root
|
6
7
|
delegate :<<, to: :children
|
7
8
|
|
8
9
|
cached_partial_path = "showcase/engine/path/tree"
|
9
10
|
define_method(:to_partial_path) { cached_partial_path }
|
10
11
|
|
11
12
|
def name
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
def root?
|
16
|
-
id == "."
|
13
|
+
id == "." ? "Previews" : id
|
17
14
|
end
|
18
15
|
|
19
16
|
def ordered_children
|
@@ -24,15 +21,10 @@ class Showcase::Path
|
|
24
21
|
children.flat_map { _1.is_a?(Tree) ? _1.ordered_paths : _1 }
|
25
22
|
end
|
26
23
|
|
27
|
-
def self.index(
|
28
|
-
new(:discardable_root)
|
29
|
-
|
30
|
-
|
31
|
-
def index(paths)
|
32
|
-
paths.each do |path|
|
33
|
-
ids = yield path
|
34
|
-
ids.inject(self, :edge_for) << path
|
35
|
-
end
|
24
|
+
def self.index(paths)
|
25
|
+
paths.each_with_object new(:discardable_root) do |path, root|
|
26
|
+
yield(path).reduce(root, :edge_for) << path
|
27
|
+
end.children.sort_by(&:id).each { _1.root = true }
|
36
28
|
end
|
37
29
|
|
38
30
|
def edge_for(id)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class Showcase::Sample
|
2
2
|
attr_reader :name, :id, :events, :details
|
3
|
-
attr_reader :source
|
3
|
+
attr_reader :source, :instrumented
|
4
4
|
|
5
5
|
def initialize(view_context, name, description: nil, id: name.parameterize, events: nil, **details)
|
6
6
|
@view_context = view_context
|
@@ -24,7 +24,13 @@ class Showcase::Sample
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def preview(&block)
|
27
|
-
|
27
|
+
return @preview unless block_given?
|
28
|
+
|
29
|
+
# TODO: Remove `is_a?` check when Rails 6.1 support is dropped.
|
30
|
+
assigns = proc { @instrumented = _1 if _1.is_a?(ActiveSupport::Notifications::Event) }
|
31
|
+
ActiveSupport::Notifications.subscribed(assigns, "render_partial.action_view") do
|
32
|
+
@preview = @view_context.capture(&block)
|
33
|
+
end
|
28
34
|
end
|
29
35
|
|
30
36
|
def extract(&block)
|
@@ -4,8 +4,8 @@
|
|
4
4
|
<title>Showcase</title>
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
6
|
|
7
|
-
<%= render "stylesheets" %>
|
8
|
-
<%= render "javascripts" %>
|
7
|
+
<%= render "showcase/engine/stylesheets" %>
|
8
|
+
<%= render "showcase/engine/javascripts" %>
|
9
9
|
</head>
|
10
10
|
|
11
11
|
<body>
|
@@ -4,7 +4,9 @@
|
|
4
4
|
<div class="sc-flex sc-items-center sc-space-x-2 sc-mb-2">
|
5
5
|
<h2 class="sc-font-semibold sc-text-3xl"><%= preview.title %></h2>
|
6
6
|
|
7
|
-
|
7
|
+
<% preview.badges.each do |badge| %>
|
8
|
+
<span class="sc-border-2 sc-border-indigo-300 sc-rounded-full sc-px-2 sc-mt-1"><%= badge.to_s.titleize %></span>
|
9
|
+
<% end %>
|
8
10
|
</div>
|
9
11
|
<% end %>
|
10
12
|
|
@@ -1,7 +1,16 @@
|
|
1
1
|
<section class="sc-mb-4 sc-border sc-border-gray-200 sc-rounded-md" aria-labelledby="showcase_<%= sample.id %>_title">
|
2
2
|
<showcase-sample id="<%= sample.id %>" events="<%= sample.events %>">
|
3
3
|
<header class="sc-bg-slate-100/50">
|
4
|
-
<
|
4
|
+
<div class="sc-flex sc-justify-between">
|
5
|
+
<h3 id="showcase_<%= sample.id %>_title" class="sc-px-4 sc-py-2 sc-font-medium sc-text-base md:sc-text-lg sc-leading-snug sc-truncate"><%= link_to sample.name, "##{sample.id}" %></h3>
|
6
|
+
|
7
|
+
<% if event = sample.instrumented %>
|
8
|
+
<div class="sc-text-xs sc-grid sc-gap-x-2 sc-m-2 sc-italic sc-text-slate-500">
|
9
|
+
<span><%= event.duration.round(1) %>ms</span>
|
10
|
+
<span><%= event.allocations %> allocs</span>
|
11
|
+
</div>
|
12
|
+
<% end %>
|
13
|
+
</div>
|
5
14
|
|
6
15
|
<% if sample.description %>
|
7
16
|
<p class="sc-px-4 sc-py-2 sc-text-base"><%= sample.description %></p>
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "active_support/option_merger"
|
2
|
+
|
3
|
+
class Showcase::Options
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize(view_context)
|
7
|
+
@view_context = view_context
|
8
|
+
@options = []
|
9
|
+
@order = [:name, :required, :type, :default, :description]
|
10
|
+
end
|
11
|
+
delegate :empty?, to: :@options
|
12
|
+
|
13
|
+
# Showcase.options.define :stimulus do
|
14
|
+
# def value(name, ...)
|
15
|
+
# option("data-#{@controller}-#{name}-value", ...)
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
singleton_class.attr_reader :contexts
|
19
|
+
@contexts = Hash.new { |h,k| h[k] = Class.new Context }
|
20
|
+
|
21
|
+
def self.define(key, &block)
|
22
|
+
contexts[key].class_eval(&block) # Lets users reopen an already defined context class.
|
23
|
+
end
|
24
|
+
|
25
|
+
# showcase.options.stimulus controller: :welcome do |o|
|
26
|
+
# o.value :greeting, default: "Hello"
|
27
|
+
# end
|
28
|
+
def context(key, **options, &block)
|
29
|
+
context = self.class.contexts.fetch(key)
|
30
|
+
context.new(@view_context, @options, **options).tap { yield _1 if block_given? }
|
31
|
+
end
|
32
|
+
|
33
|
+
def required(*arguments, **keywords, &block)
|
34
|
+
if arguments.none?
|
35
|
+
ActiveSupport::OptionMerger.new(self, required: true)
|
36
|
+
else
|
37
|
+
option(*arguments, **keywords, required: true, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def optional(*arguments, **keywords, &block)
|
42
|
+
if arguments.none?
|
43
|
+
ActiveSupport::OptionMerger.new(self, required: false)
|
44
|
+
else
|
45
|
+
option(*arguments, **keywords, required: false, &block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
DEFAULT_OMITTED = Object.new
|
50
|
+
|
51
|
+
def option(name, description = nil, required: false, type: nil, default: DEFAULT_OMITTED, **options, &block)
|
52
|
+
description ||= @view_context.capture(&block).remove(/^\s+/).html_safe if block
|
53
|
+
|
54
|
+
type ||= type_from_default(default)
|
55
|
+
default = default == DEFAULT_OMITTED ? nil : default.inspect
|
56
|
+
|
57
|
+
@options << options.with_defaults(name: name, default: default, type: type, description: description, required: required)
|
58
|
+
end
|
59
|
+
|
60
|
+
def headers
|
61
|
+
@headers ||= @order | @options.flat_map(&:keys).uniq.sort
|
62
|
+
end
|
63
|
+
|
64
|
+
def each(&block)
|
65
|
+
@options.each do |option|
|
66
|
+
yield headers.index_with { option[_1] }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
class Context < Showcase::Options
|
73
|
+
def initialize(view_context, options, **kwargs)
|
74
|
+
super(view_context)
|
75
|
+
@options = options
|
76
|
+
kwargs.each { instance_variable_set(:"@#{_1}", _2) }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def type_from_default(default)
|
81
|
+
case default
|
82
|
+
when DEFAULT_OMITTED then String
|
83
|
+
when true, false then "Boolean"
|
84
|
+
when nil then "nil"
|
85
|
+
else
|
86
|
+
default.class
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/showcase/version.rb
CHANGED
data/lib/showcase.rb
CHANGED
@@ -3,6 +3,7 @@ require_relative "showcase/version"
|
|
3
3
|
module Showcase
|
4
4
|
autoload :IntegrationTest, "showcase/integration_test"
|
5
5
|
autoload :RouteHelper, "showcase/route_helper"
|
6
|
+
autoload :Options, "showcase/options"
|
6
7
|
|
7
8
|
singleton_class.attr_accessor :sample_renderer
|
8
9
|
@sample_renderer = ->(lines) { tag.pre lines.join.strip_heredoc }
|
@@ -15,6 +16,38 @@ module Showcase
|
|
15
16
|
Dir.glob("**/*.*", base: File.join(root, previews_path))
|
16
17
|
end.uniq
|
17
18
|
end
|
19
|
+
|
20
|
+
def self.options
|
21
|
+
Options
|
22
|
+
end
|
23
|
+
|
24
|
+
options.define :stimulus do
|
25
|
+
def targets(name, ...)
|
26
|
+
option(%(data-#{@controller}-target="#{name}"), ...)
|
27
|
+
end
|
28
|
+
|
29
|
+
def values(name, ...)
|
30
|
+
option("data-#{@controller}-#{name}-value", ...)
|
31
|
+
end
|
32
|
+
|
33
|
+
def classes(name, ...)
|
34
|
+
option("data-#{@controller}-#{name}-class", ...)
|
35
|
+
end
|
36
|
+
|
37
|
+
def outlet(name, ...)
|
38
|
+
option("data-#{@controller}-#{name}-outlet", ...)
|
39
|
+
end
|
40
|
+
|
41
|
+
def action(name, ...)
|
42
|
+
option(%(data-action="#{name}"), ...)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
options.define :nice_partials do
|
47
|
+
def content_block(*arguments, **options, &block)
|
48
|
+
option(*arguments, **options, type: "Content Block", &block)
|
49
|
+
end
|
50
|
+
end
|
18
51
|
end
|
19
52
|
|
20
53
|
require "showcase/engine" if defined?(Rails::Engine)
|
@@ -2,9 +2,9 @@ namespace :showcase do
|
|
2
2
|
namespace :install do
|
3
3
|
INTEGRATION_TEST_PATH = "test/integration/showcase_test.rb"
|
4
4
|
|
5
|
-
desc "Install Showcase
|
6
|
-
task :
|
7
|
-
mkdir_p INTEGRATION_TEST_PATH
|
5
|
+
desc "Install Showcase integration testing in #{INTEGRATION_TEST_PATH}"
|
6
|
+
task :integration_test do
|
7
|
+
mkdir_p File.dirname(INTEGRATION_TEST_PATH)
|
8
8
|
File.write INTEGRATION_TEST_PATH, <<~RUBY
|
9
9
|
require "test_helper"
|
10
10
|
|
@@ -16,15 +16,4 @@ namespace :showcase do
|
|
16
16
|
RUBY
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
20
|
-
# desc "Pass a directory relative to app/views to copy over"
|
21
|
-
# task :copy do |t, directory|
|
22
|
-
# prefix = "app/views/#{directory}"
|
23
|
-
#
|
24
|
-
# Dir.glob(File.join(Dir.pwd, prefix, "**/*.*")).each do |filename|
|
25
|
-
# new_filename = filename.sub(directory, Showcase.templates_path).sub(/\/_/, "/")
|
26
|
-
# mkdir_p File.dirname(new_filename)
|
27
|
-
# copy_file filename, new_filename
|
28
|
-
# end
|
29
|
-
# end
|
30
19
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: showcase-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Pence
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-02-
|
12
|
+
date: 2023-02-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -53,9 +53,7 @@ files:
|
|
53
53
|
- app/assets/config/showcase_manifest.js
|
54
54
|
- app/assets/javascripts/showcase.js
|
55
55
|
- app/controllers/showcase/engine_controller.rb
|
56
|
-
- app/controllers/showcase/pages_controller.rb
|
57
56
|
- app/controllers/showcase/previews_controller.rb
|
58
|
-
- app/models/showcase/options.rb
|
59
57
|
- app/models/showcase/path.rb
|
60
58
|
- app/models/showcase/preview.rb
|
61
59
|
- app/models/showcase/sample.rb
|
@@ -76,6 +74,7 @@ files:
|
|
76
74
|
- lib/showcase.rb
|
77
75
|
- lib/showcase/engine.rb
|
78
76
|
- lib/showcase/integration_test.rb
|
77
|
+
- lib/showcase/options.rb
|
79
78
|
- lib/showcase/route_helper.rb
|
80
79
|
- lib/showcase/version.rb
|
81
80
|
- lib/tasks/showcase_tasks.rake
|
@@ -101,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
100
|
- !ruby/object:Gem::Version
|
102
101
|
version: '0'
|
103
102
|
requirements: []
|
104
|
-
rubygems_version: 3.4.
|
103
|
+
rubygems_version: 3.4.7
|
105
104
|
signing_key:
|
106
105
|
specification_version: 4
|
107
106
|
summary: Showcase helps you show off and document your partials, components, view
|
@@ -1,51 +0,0 @@
|
|
1
|
-
class Showcase::Options
|
2
|
-
include Enumerable
|
3
|
-
|
4
|
-
def initialize(view_context)
|
5
|
-
@view_context = view_context
|
6
|
-
@options = []
|
7
|
-
@order = [:name, :required, :type, :default, :description]
|
8
|
-
end
|
9
|
-
delegate :empty?, to: :@options
|
10
|
-
|
11
|
-
def required(*arguments, **keywords, &block)
|
12
|
-
option(*arguments, **keywords, required: true, &block)
|
13
|
-
end
|
14
|
-
|
15
|
-
def optional(*arguments, **keywords, &block)
|
16
|
-
option(*arguments, **keywords, required: false, &block)
|
17
|
-
end
|
18
|
-
|
19
|
-
DEFAULT_OMITTED = Object.new
|
20
|
-
|
21
|
-
def option(name, description = nil, required: false, type: nil, default: DEFAULT_OMITTED, **options, &block)
|
22
|
-
description ||= @view_context.capture(&block).remove(/^\s+/).html_safe if block
|
23
|
-
|
24
|
-
type ||= type_from_default(default)
|
25
|
-
default = default == DEFAULT_OMITTED ? nil : default.inspect
|
26
|
-
|
27
|
-
@options << options.with_defaults(name: name, default: default, type: type, description: description, required: required)
|
28
|
-
end
|
29
|
-
|
30
|
-
def headers
|
31
|
-
@headers ||= @order | @options.flat_map(&:keys).uniq.sort
|
32
|
-
end
|
33
|
-
|
34
|
-
def each(&block)
|
35
|
-
@options.each do |option|
|
36
|
-
yield headers.index_with { option[_1] }
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def type_from_default(default)
|
43
|
-
case default
|
44
|
-
when DEFAULT_OMITTED then String
|
45
|
-
when true, false then "Boolean"
|
46
|
-
when nil then "nil"
|
47
|
-
else
|
48
|
-
default.class
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|