showcase-rails 0.1.1 → 0.2.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 +4 -4
- data/README.md +76 -7
- data/app/assets/builds/showcase.css +78 -78
- data/app/controllers/showcase/engine_controller.rb +12 -0
- data/app/controllers/showcase/pages_controller.rb +1 -4
- data/app/controllers/showcase/previews_controller.rb +5 -0
- data/app/models/showcase/{page/options.rb → options.rb} +1 -1
- data/app/models/showcase/path.rb +49 -12
- data/app/models/showcase/preview.rb +94 -0
- data/app/models/showcase/{page/sample.rb → sample.rb} +10 -6
- data/app/views/layouts/showcase.html.erb +3 -3
- data/app/views/showcase/engine/_javascripts.html.erb +1 -0
- data/app/views/showcase/engine/_options.html.erb +29 -0
- data/app/views/showcase/engine/_preview.html.erb +26 -0
- data/app/views/showcase/engine/_root.html.erb +13 -0
- data/app/views/showcase/engine/_sample.html.erb +37 -0
- data/app/views/showcase/engine/_stylesheets.html.erb +1 -0
- data/app/views/showcase/engine/index.html.erb +33 -0
- data/app/views/showcase/engine/path/_path.html.erb +3 -0
- data/app/views/showcase/engine/path/_tree.html.erb +4 -0
- data/app/views/showcase/engine/show.html.erb +1 -0
- data/config/routes.rb +2 -2
- data/config/tailwind.config.js +1 -0
- data/lib/showcase/integration_test.rb +23 -0
- data/lib/showcase/route_helper.rb +8 -0
- data/lib/showcase/version.rb +1 -1
- data/lib/showcase.rb +14 -10
- data/lib/tasks/showcase_tasks.rake +30 -4
- metadata +20 -14
- data/app/controllers/showcase/application_controller.rb +0 -3
- data/app/models/showcase/page.rb +0 -45
- data/app/views/showcase/_root.html.erb +0 -13
- data/app/views/showcase/pages/_options.html.erb +0 -27
- data/app/views/showcase/pages/_page.html.erb +0 -26
- data/app/views/showcase/pages/_sample.html.erb +0 -37
- data/app/views/showcase/pages/index.html.erb +0 -33
- data/app/views/showcase/pages/show.html.erb +0 -1
- data/app/views/showcase/path/_tree.html.erb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38aa85b8e5c0a98ee2dbb45f0a184981de8a86371efbb2237e2a06f0d2f56eef
|
4
|
+
data.tar.gz: b4e44e25c0b76afcd33a2dc155cae5bdebe1a5a9ca3cd670d4cc2bae94d7f38b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 995f0b2b6f765c93936adb968c501218fccc592befe12df06e0aa19b9b092a0ea385cab086763f0b855e3e86eb784edf8365143b49e69dbda934bd8ce608016d
|
7
|
+
data.tar.gz: 123c59c68801489dec09d40c144c64fbc09dc6c65925833cbeade7a4c8f479595b6d59274d3ab7e74cdd18495dd8276ef60fa714b3f87662c786d6c190d55c39
|
data/README.md
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
# Showcase
|
2
2
|
|
3
|
-
Showcase lets you build previews for partials, components, view helpers
|
3
|
+
Showcase lets you build previews for your partials, components, view helpers, Stimulus controllers and more.
|
4
4
|
|
5
|
-
Add a
|
5
|
+
Add a template to `app/views/showcase/previews` and it'll show up in Showcase's menu.
|
6
6
|
|
7
7
|
Here's how to showcase a standard button component:
|
8
8
|
|
9
9
|
```erb
|
10
|
-
<%# app/views/
|
10
|
+
<%# app/views/showcase/previews/_button.html.erb %>
|
11
|
+
<% showcase.title "Button" %> <%# `title` is optional and inferred from the filename, by default. %>
|
11
12
|
<% showcase.description "This button component handles what we click on" %>
|
12
13
|
|
13
14
|
<% showcase.sample "Basic" do %>
|
@@ -19,17 +20,85 @@ Here's how to showcase a standard button component:
|
|
19
20
|
<% end %>
|
20
21
|
|
21
22
|
<% showcase.options do |o| %>
|
22
|
-
<% o.required :content,
|
23
|
-
<% o.optional :mode, default: :small,
|
23
|
+
<% o.required :content, "The content to output as the button text" %>
|
24
|
+
<% o.optional :mode, "We support three modes", default: :small, options: %i[ small medium large ] %>
|
24
25
|
<% end %>
|
25
26
|
```
|
26
27
|
|
28
|
+
Which will then render the following:
|
29
|
+
|
30
|
+

|
31
|
+
|
32
|
+
## Automatic smokescreen testing
|
33
|
+
|
34
|
+
Run `bin/rails showcase:install:integration_test` to automatic testing installed in `test/integration/showcase_test.rb`.
|
35
|
+
|
36
|
+
This will render every Showcase you've defined and assert they respond with `200 OK`. You can add custom assertions by overriding `assert_showcase_preview`.
|
37
|
+
|
38
|
+
## View examples
|
39
|
+
|
40
|
+
Clone the repository, run `bundle install`, then run `bin/rails server`, visit localhost:3000 in your browser.
|
41
|
+
|
42
|
+
## Overriding Showcase's default rendering
|
43
|
+
|
44
|
+
Showcase's rendering happens through two controllers:
|
45
|
+
|
46
|
+
1. [`Showcase::EngineController`](app/controllers/showcase/engine_controller.rb)
|
47
|
+
1. [`Showcase::PreviewsController`](app/controllers/showcase/previews_controller.rb)
|
48
|
+
|
49
|
+
All paths shown here are assumed to be in `app/views`.
|
50
|
+
|
51
|
+
The actions all use a `layout "showcase"`, which renders like this:
|
52
|
+
|
53
|
+
- [layouts/showcase.html.erb](app/views/layouts/showcase.html.erb)
|
54
|
+
- [showcase/engine/_root.html.erb](app/views/showcase/engine/_root.html.erb)
|
55
|
+
- [showcase/engine/path/_tree.html.erb](app/views/showcase/engine/path/_tree.html.erb)
|
56
|
+
|
57
|
+
So for `Showcase::EngineController#index` we render:
|
58
|
+
|
59
|
+
- [showcase/engine/index.html.erb](app/views/showcase/engine/index.html.erb)
|
60
|
+
|
61
|
+
And for `Showcase::PreviewsController#show` we render:
|
62
|
+
|
63
|
+
- [showcase/engine/show.html.erb](app/views/showcase/engine/show.html.erb)
|
64
|
+
- [showcase/engine/_preview.html.erb](app/views/showcase/engine/_preview.html.erb)
|
65
|
+
- [showcase/engine/_sample.html.erb](app/views/showcase/engine/_sample.html.erb)
|
66
|
+
- [showcase/engine/_options.html.erb](app/views/showcase/engine/_options.html.erb)
|
67
|
+
|
68
|
+
If you want to override any specific rendering, e.g. how a `Showcase::Preview` is rendered,
|
69
|
+
copy the file from our repo `app/views` directory into your `app/views` directory.
|
70
|
+
|
71
|
+
### Loading your own assets
|
72
|
+
|
73
|
+
Showcase bundles its own `showcase.js` and `showcase.css` asset files through
|
74
|
+
Action View's [javascript_include_tag][] and [stylesheet_link_tag][].
|
75
|
+
|
76
|
+
If your assets require more sophisticated loading techniques, declare your own
|
77
|
+
versions of the [showcase/engine/_javascripts.html.erb][] and
|
78
|
+
[showcase/engine/_stylesheets.html.erb][] partials. When customizing those
|
79
|
+
partials, make sure to include `"showcase"` in your list of assets.
|
80
|
+
|
81
|
+
|
82
|
+
[javascript_include_tag]: https://edgeapi.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#method-i-javascript_include_tag
|
83
|
+
[stylesheet_link_tag]: https://edgeapi.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#method-i-stylesheet_link_tag
|
84
|
+
[showcase/engine/_javascripts.html.erb]: ./showcase/engine/_javascripts.html.erb
|
85
|
+
[showcase/engine/_stylesheets.html.erb]: ./showcase/engine/_stylesheets.html.erb
|
86
|
+
|
27
87
|
## Installation
|
28
88
|
|
29
|
-
Add this line to your application's Gemfile
|
89
|
+
Add this line to your application's Gemfile. If you're utilizing the
|
90
|
+
[Showcase::IntegrationTest](lib/showcase/integration_test.rb) class, make sure
|
91
|
+
that the `showcase-rails` gems is available to your test environment:
|
92
|
+
|
30
93
|
|
31
94
|
```ruby
|
32
|
-
|
95
|
+
# nested in the default group
|
96
|
+
gem "showcase-rails"
|
97
|
+
|
98
|
+
# or nested in the :development and :test groups
|
99
|
+
group :development, :test do
|
100
|
+
gem "showcase-rails"
|
101
|
+
end
|
33
102
|
```
|
34
103
|
|
35
104
|
And then execute:
|
@@ -679,280 +679,280 @@ select {
|
|
679
679
|
--tw-backdrop-sepia: ;
|
680
680
|
}
|
681
681
|
|
682
|
-
.relative {
|
682
|
+
.sc-relative {
|
683
683
|
position: relative;
|
684
684
|
}
|
685
685
|
|
686
|
-
.col-span-3 {
|
686
|
+
.sc-col-span-3 {
|
687
687
|
grid-column: span 3 / span 3;
|
688
688
|
}
|
689
689
|
|
690
|
-
.col-span-9 {
|
690
|
+
.sc-col-span-9 {
|
691
691
|
grid-column: span 9 / span 9;
|
692
692
|
}
|
693
693
|
|
694
|
-
.mb-2 {
|
694
|
+
.sc-mb-2 {
|
695
695
|
margin-bottom: 0.5rem;
|
696
696
|
}
|
697
697
|
|
698
|
-
.mb-4 {
|
698
|
+
.sc-mb-4 {
|
699
699
|
margin-bottom: 1rem;
|
700
700
|
}
|
701
701
|
|
702
|
-
.inline-block {
|
702
|
+
.sc-inline-block {
|
703
703
|
display: inline-block;
|
704
704
|
}
|
705
705
|
|
706
|
-
.flex {
|
706
|
+
.sc-flex {
|
707
707
|
display: flex;
|
708
708
|
}
|
709
709
|
|
710
|
-
.table {
|
710
|
+
.sc-table {
|
711
711
|
display: table;
|
712
712
|
}
|
713
713
|
|
714
|
-
.grid {
|
714
|
+
.sc-grid {
|
715
715
|
display: grid;
|
716
716
|
}
|
717
717
|
|
718
|
-
.h-full {
|
718
|
+
.sc-h-full {
|
719
719
|
height: 100%;
|
720
720
|
}
|
721
721
|
|
722
|
-
.max-h-20 {
|
722
|
+
.sc-max-h-20 {
|
723
723
|
max-height: 5rem;
|
724
724
|
}
|
725
725
|
|
726
|
-
.min-h-screen {
|
726
|
+
.sc-min-h-screen {
|
727
727
|
min-height: 100vh;
|
728
728
|
}
|
729
729
|
|
730
|
-
.w-full {
|
730
|
+
.sc-w-full {
|
731
731
|
width: 100%;
|
732
732
|
}
|
733
733
|
|
734
|
-
.border-collapse {
|
734
|
+
.sc-border-collapse {
|
735
735
|
border-collapse: collapse;
|
736
736
|
}
|
737
737
|
|
738
|
-
.cursor-pointer {
|
738
|
+
.sc-cursor-pointer {
|
739
739
|
cursor: pointer;
|
740
740
|
}
|
741
741
|
|
742
|
-
.select-none {
|
742
|
+
.sc-select-none {
|
743
743
|
-webkit-user-select: none;
|
744
744
|
-moz-user-select: none;
|
745
745
|
user-select: none;
|
746
746
|
}
|
747
747
|
|
748
|
-
.list-none {
|
748
|
+
.sc-list-none {
|
749
749
|
list-style-type: none;
|
750
750
|
}
|
751
751
|
|
752
|
-
.grid-cols-12 {
|
752
|
+
.sc-grid-cols-12 {
|
753
753
|
grid-template-columns: repeat(12, minmax(0, 1fr));
|
754
754
|
}
|
755
755
|
|
756
|
-
.flex-col {
|
756
|
+
.sc-flex-col {
|
757
757
|
flex-direction: column;
|
758
758
|
}
|
759
759
|
|
760
|
-
.flex-wrap {
|
760
|
+
.sc-flex-wrap {
|
761
761
|
flex-wrap: wrap;
|
762
762
|
}
|
763
763
|
|
764
|
-
.items-center {
|
764
|
+
.sc-items-center {
|
765
765
|
align-items: center;
|
766
766
|
}
|
767
767
|
|
768
|
-
.space-y-8 > :not([hidden]) ~ :not([hidden]) {
|
768
|
+
.sc-space-y-8 > :not([hidden]) ~ :not([hidden]) {
|
769
769
|
--tw-space-y-reverse: 0;
|
770
770
|
margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));
|
771
771
|
margin-bottom: calc(2rem * var(--tw-space-y-reverse));
|
772
772
|
}
|
773
773
|
|
774
|
-
.space-x-2 > :not([hidden]) ~ :not([hidden]) {
|
774
|
+
.sc-space-x-2 > :not([hidden]) ~ :not([hidden]) {
|
775
775
|
--tw-space-x-reverse: 0;
|
776
776
|
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
|
777
777
|
margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse)));
|
778
778
|
}
|
779
779
|
|
780
|
-
.space-y-4 > :not([hidden]) ~ :not([hidden]) {
|
780
|
+
.sc-space-y-4 > :not([hidden]) ~ :not([hidden]) {
|
781
781
|
--tw-space-y-reverse: 0;
|
782
782
|
margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
|
783
783
|
margin-bottom: calc(1rem * var(--tw-space-y-reverse));
|
784
784
|
}
|
785
785
|
|
786
|
-
.overflow-
|
787
|
-
overflow: hidden;
|
788
|
-
}
|
789
|
-
|
790
|
-
.overflow-scroll {
|
786
|
+
.sc-overflow-scroll {
|
791
787
|
overflow: scroll;
|
792
788
|
}
|
793
789
|
|
794
|
-
.overflow-x-auto {
|
790
|
+
.sc-overflow-x-auto {
|
795
791
|
overflow-x: auto;
|
796
792
|
}
|
797
793
|
|
798
|
-
.
|
794
|
+
.sc-overflow-y-auto {
|
795
|
+
overflow-y: auto;
|
796
|
+
}
|
797
|
+
|
798
|
+
.sc-truncate {
|
799
799
|
overflow: hidden;
|
800
800
|
text-overflow: ellipsis;
|
801
801
|
white-space: nowrap;
|
802
802
|
}
|
803
803
|
|
804
|
-
.rounded-md {
|
804
|
+
.sc-rounded-md {
|
805
805
|
border-radius: 0.375rem;
|
806
806
|
}
|
807
807
|
|
808
|
-
.border {
|
808
|
+
.sc-border {
|
809
809
|
border-width: 1px;
|
810
810
|
}
|
811
811
|
|
812
|
-
.border-0 {
|
812
|
+
.sc-border-0 {
|
813
813
|
border-width: 0px;
|
814
814
|
}
|
815
815
|
|
816
|
-
.border-
|
817
|
-
border-
|
816
|
+
.sc-border-t {
|
817
|
+
border-top-width: 1px;
|
818
818
|
}
|
819
819
|
|
820
|
-
.border-
|
821
|
-
border-
|
820
|
+
.sc-border-r {
|
821
|
+
border-right-width: 1px;
|
822
822
|
}
|
823
823
|
|
824
|
-
.border-b {
|
824
|
+
.sc-border-b {
|
825
825
|
border-bottom-width: 1px;
|
826
826
|
}
|
827
827
|
|
828
|
-
.border-gray-200 {
|
828
|
+
.sc-border-gray-200 {
|
829
829
|
--tw-border-opacity: 1;
|
830
830
|
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
831
831
|
}
|
832
832
|
|
833
|
-
.bg-slate-50 {
|
833
|
+
.sc-bg-slate-50 {
|
834
834
|
--tw-bg-opacity: 1;
|
835
835
|
background-color: rgb(248 250 252 / var(--tw-bg-opacity));
|
836
836
|
}
|
837
837
|
|
838
|
-
.bg-slate-100\/50 {
|
838
|
+
.sc-bg-slate-100\/50 {
|
839
839
|
background-color: rgb(241 245 249 / 0.5);
|
840
840
|
}
|
841
841
|
|
842
|
-
.bg-indigo-50 {
|
842
|
+
.sc-bg-indigo-50 {
|
843
843
|
--tw-bg-opacity: 1;
|
844
844
|
background-color: rgb(238 242 255 / var(--tw-bg-opacity));
|
845
845
|
}
|
846
846
|
|
847
|
-
.p-
|
848
|
-
padding:
|
847
|
+
.sc-p-4 {
|
848
|
+
padding: 1rem;
|
849
849
|
}
|
850
850
|
|
851
|
-
.p-
|
852
|
-
padding:
|
851
|
+
.sc-p-12 {
|
852
|
+
padding: 3rem;
|
853
853
|
}
|
854
854
|
|
855
|
-
.
|
856
|
-
padding-
|
857
|
-
padding-
|
855
|
+
.sc-px-4 {
|
856
|
+
padding-left: 1rem;
|
857
|
+
padding-right: 1rem;
|
858
858
|
}
|
859
859
|
|
860
|
-
.py-2 {
|
860
|
+
.sc-py-2 {
|
861
861
|
padding-top: 0.5rem;
|
862
862
|
padding-bottom: 0.5rem;
|
863
863
|
}
|
864
864
|
|
865
|
-
.
|
866
|
-
padding-
|
867
|
-
padding-
|
865
|
+
.sc-py-5 {
|
866
|
+
padding-top: 1.25rem;
|
867
|
+
padding-bottom: 1.25rem;
|
868
868
|
}
|
869
869
|
|
870
|
-
.px-8 {
|
870
|
+
.sc-px-8 {
|
871
871
|
padding-left: 2rem;
|
872
872
|
padding-right: 2rem;
|
873
873
|
}
|
874
874
|
|
875
|
-
.pl-4 {
|
875
|
+
.sc-pl-4 {
|
876
876
|
padding-left: 1rem;
|
877
877
|
}
|
878
878
|
|
879
|
-
.pt-7 {
|
879
|
+
.sc-pt-7 {
|
880
880
|
padding-top: 1.75rem;
|
881
881
|
}
|
882
882
|
|
883
|
-
.text-
|
884
|
-
font-size: 1.5rem;
|
885
|
-
line-height: 2rem;
|
886
|
-
}
|
887
|
-
|
888
|
-
.text-xl {
|
883
|
+
.sc-text-xl {
|
889
884
|
font-size: 1.25rem;
|
890
885
|
line-height: 1.75rem;
|
891
886
|
}
|
892
887
|
|
893
|
-
.text-3xl {
|
888
|
+
.sc-text-3xl {
|
894
889
|
font-size: 1.875rem;
|
895
890
|
line-height: 2.25rem;
|
896
891
|
}
|
897
892
|
|
898
|
-
.text-base {
|
893
|
+
.sc-text-base {
|
899
894
|
font-size: 1rem;
|
900
895
|
line-height: 1.5rem;
|
901
896
|
}
|
902
897
|
|
903
|
-
.
|
904
|
-
font-
|
898
|
+
.sc-text-2xl {
|
899
|
+
font-size: 1.5rem;
|
900
|
+
line-height: 2rem;
|
905
901
|
}
|
906
902
|
|
907
|
-
.font-semibold {
|
903
|
+
.sc-font-semibold {
|
908
904
|
font-weight: 600;
|
909
905
|
}
|
910
906
|
|
911
|
-
.font-normal {
|
907
|
+
.sc-font-normal {
|
912
908
|
font-weight: 400;
|
913
909
|
}
|
914
910
|
|
915
|
-
.font-
|
911
|
+
.sc-font-black {
|
912
|
+
font-weight: 900;
|
913
|
+
}
|
914
|
+
|
915
|
+
.sc-font-medium {
|
916
916
|
font-weight: 500;
|
917
917
|
}
|
918
918
|
|
919
|
-
.italic {
|
919
|
+
.sc-italic {
|
920
920
|
font-style: italic;
|
921
921
|
}
|
922
922
|
|
923
|
-
.leading-snug {
|
923
|
+
.sc-leading-snug {
|
924
924
|
line-height: 1.375;
|
925
925
|
}
|
926
926
|
|
927
|
-
.text-black {
|
927
|
+
.sc-text-black {
|
928
928
|
--tw-text-opacity: 1;
|
929
929
|
color: rgb(0 0 0 / var(--tw-text-opacity));
|
930
930
|
}
|
931
931
|
|
932
|
-
.hover\:select-all:hover {
|
932
|
+
.hover\:sc-select-all:hover {
|
933
933
|
-webkit-user-select: all;
|
934
934
|
-moz-user-select: all;
|
935
935
|
user-select: all;
|
936
936
|
}
|
937
937
|
|
938
|
-
.hover\:bg-indigo-50:hover {
|
938
|
+
.hover\:sc-bg-indigo-50:hover {
|
939
939
|
--tw-bg-opacity: 1;
|
940
940
|
background-color: rgb(238 242 255 / var(--tw-bg-opacity));
|
941
941
|
}
|
942
942
|
|
943
943
|
@media (min-width: 768px) {
|
944
|
-
.md\:text-lg {
|
944
|
+
.md\:sc-text-lg {
|
945
945
|
font-size: 1.125rem;
|
946
946
|
line-height: 1.75rem;
|
947
947
|
}
|
948
948
|
}
|
949
949
|
|
950
950
|
@media (min-width: 1280px) {
|
951
|
-
.xl\:col-span-2 {
|
951
|
+
.xl\:sc-col-span-2 {
|
952
952
|
grid-column: span 2 / span 2;
|
953
953
|
}
|
954
954
|
|
955
|
-
.xl\:col-span-10 {
|
955
|
+
.xl\:sc-col-span-10 {
|
956
956
|
grid-column: span 10 / span 10;
|
957
957
|
}
|
958
958
|
}
|
data/app/models/showcase/path.rb
CHANGED
@@ -1,30 +1,67 @@
|
|
1
1
|
class Showcase::Path
|
2
|
-
class Tree < Struct.new(:id, :
|
2
|
+
class Tree < Struct.new(:id, :children)
|
3
|
+
def initialize(id, children = [])
|
4
|
+
super
|
5
|
+
end
|
6
|
+
delegate :<<, to: :children
|
7
|
+
|
8
|
+
cached_partial_path = "showcase/engine/path/tree"
|
9
|
+
define_method(:to_partial_path) { cached_partial_path }
|
10
|
+
|
3
11
|
def name
|
4
|
-
root? ? "
|
12
|
+
root? ? "Previews" : id
|
5
13
|
end
|
6
14
|
|
7
15
|
def root?
|
8
16
|
id == "."
|
9
17
|
end
|
10
|
-
end
|
11
18
|
|
12
|
-
|
13
|
-
|
19
|
+
def ordered_children
|
20
|
+
children.partition { !_1.is_a?(Tree) }.flatten
|
21
|
+
end
|
22
|
+
|
23
|
+
def ordered_paths
|
24
|
+
children.flat_map { _1.is_a?(Tree) ? _1.ordered_paths : _1 }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.index(...)
|
28
|
+
new(:discardable_root).tap { _1.index(...) }.ordered_children
|
29
|
+
end
|
30
|
+
|
31
|
+
def index(paths)
|
32
|
+
paths.each do |path|
|
33
|
+
ids = yield path
|
34
|
+
ids.inject(self, :edge_for) << path
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def edge_for(id)
|
39
|
+
find(id) || insert(id)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def find(id) = children.find { _1.id == id }
|
45
|
+
def insert(id) = self.class.new(id).tap { self << _1 }
|
14
46
|
end
|
15
47
|
|
16
|
-
def self.
|
17
|
-
Showcase.
|
48
|
+
def self.tree
|
49
|
+
paths = Showcase.previews.map { new _1 }.sort_by!(&:id)
|
50
|
+
Tree.index(paths, &:segments)
|
18
51
|
end
|
19
52
|
|
20
|
-
attr_reader :id, :
|
53
|
+
attr_reader :id, :segments, :basename
|
21
54
|
|
22
55
|
def initialize(path)
|
23
|
-
@id = path.split(".").first
|
24
|
-
@
|
56
|
+
@id = path.split(".").first.delete_prefix("_").sub(/\/_/, "/")
|
57
|
+
@basename = File.basename(@id)
|
58
|
+
@segments = File.dirname(@id).split("/")
|
25
59
|
end
|
26
60
|
|
27
|
-
|
28
|
-
|
61
|
+
cached_partial_path = "showcase/engine/path/path"
|
62
|
+
define_method(:to_partial_path) { cached_partial_path }
|
63
|
+
|
64
|
+
def preview_for(view_context)
|
65
|
+
Showcase::Preview.new(view_context, id: id, title: basename.titleize).tap(&:render_associated_partial)
|
29
66
|
end
|
30
67
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
class Showcase::Preview
|
2
|
+
attr_reader :id, :badges, :samples
|
3
|
+
|
4
|
+
def initialize(view_context, id:, title: nil)
|
5
|
+
@view_context, @id = view_context, id
|
6
|
+
@badges, @samples = [], []
|
7
|
+
title title
|
8
|
+
end
|
9
|
+
|
10
|
+
# Set a custom title for the Preview. By default, it's automatically inferred from the sidebar title,
|
11
|
+
# e.g. showcase/previews/_button.html.erb will have Button as the title.
|
12
|
+
def title(content = nil)
|
13
|
+
@title = content if content
|
14
|
+
@title
|
15
|
+
end
|
16
|
+
|
17
|
+
# Describe the Preview in more detail to help guide other developers on what the inner partial/component etc.'s purpose is.
|
18
|
+
#
|
19
|
+
# <% showcase.description "Our button element" %>
|
20
|
+
# <% showcase.description do %>
|
21
|
+
# <h3>Our button element</h3> — <span>but with custom description HTML</span>
|
22
|
+
# <% end %>
|
23
|
+
def description(content = nil, &block)
|
24
|
+
@description = content || @view_context.capture(&block) if content || block_given?
|
25
|
+
@description
|
26
|
+
end
|
27
|
+
|
28
|
+
# Optional badges you can give to a preview:
|
29
|
+
#
|
30
|
+
# <% showcase.badge :partial, :view_helper %>
|
31
|
+
def badge(*badges)
|
32
|
+
@badges.concat badges
|
33
|
+
end
|
34
|
+
|
35
|
+
# Adds a named sample to demonstrate with the Showcase can do.
|
36
|
+
#
|
37
|
+
# By default, sample takes a block that'll automatically have its source extracted, like this:
|
38
|
+
#
|
39
|
+
# <% showcase.sample "Basic" do %>
|
40
|
+
# <%= render "components/button", content: "Button Content", mode: :small %>
|
41
|
+
# <% end %>
|
42
|
+
#
|
43
|
+
# This outputs a `<showcase-sample>` custom HTML element.
|
44
|
+
# The sample name is used to generate the `id` via `name.parameterize` by default, pass `id:` to override.
|
45
|
+
#
|
46
|
+
# If more advanced rendering is needed, the sample is available as a block argument:
|
47
|
+
#
|
48
|
+
# <% showcase.sample "Advanced" do |sample| %>
|
49
|
+
# <% sample.preview do %>
|
50
|
+
# <%= render "components/button", content: "Button Content", mode: :small %>
|
51
|
+
# <% end %>
|
52
|
+
#
|
53
|
+
# <% sample.extract do %>
|
54
|
+
# This will be in the source output.
|
55
|
+
# <% end %>
|
56
|
+
#
|
57
|
+
# The sample also supports several extra options:
|
58
|
+
#
|
59
|
+
# <% showcase.sample "Basic", id: "custom-id", description: "Please use this", events: "toggle:toggled", custom: "option" do %>
|
60
|
+
# <%# … %>
|
61
|
+
# <% end %>
|
62
|
+
#
|
63
|
+
# Here we set:
|
64
|
+
# - the `sample.id` with the HTML element `id` is overriden
|
65
|
+
# - the `sample.description`
|
66
|
+
# - the `sample.events` what JavaScript `events` to listen for on the element
|
67
|
+
# - any other custom options are available in `sample.details`.
|
68
|
+
def sample(name, **options, &block)
|
69
|
+
@samples << Showcase::Sample.new(@view_context, name, **options).tap { _1.collect(&block) }
|
70
|
+
end
|
71
|
+
|
72
|
+
# Yields an Options object to help define the configuration table for a Preview.
|
73
|
+
#
|
74
|
+
# <% showcase.options do |o| %>
|
75
|
+
# <% o.required :content, "Pass the inner content text that the button should display" %>
|
76
|
+
# <% o.optional :mode, "Pass an optional mode override", default: :small, options: %i[ small medium large ] %>
|
77
|
+
# <% o.optional :method, "What HTTP method to use", type: "String | Symbol", default: :post %>
|
78
|
+
# <% o.optional :reversed, "Whether the inner text should be reversed", default: false %> # type: "Boolean" is inferred from the default here.
|
79
|
+
# <% o.optional "**options", "Every other option is passed on as options to the inner `button_tag`", type: Hash %>
|
80
|
+
# <% end %>
|
81
|
+
#
|
82
|
+
# The `type:` is derived if a `default:` is passed, otherwise it's assumed to be a String.
|
83
|
+
#
|
84
|
+
# Showcase outputs the columns with this order [:name, :required, :type, :default, :description], any other passed column is
|
85
|
+
# automatically rendered after those.
|
86
|
+
def options
|
87
|
+
@options ||= Showcase::Options.new(@view_context).tap { yield _1 if block_given? }
|
88
|
+
end
|
89
|
+
|
90
|
+
def render_associated_partial
|
91
|
+
@view_context.render "#{Showcase.previews_path}/#{id}", showcase: self
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
end
|