f_components 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +144 -0
  3. data/Rakefile +20 -0
  4. data/app/components/f_components/avatar/component.html.erb +1 -0
  5. data/app/components/f_components/avatar/component.rb +30 -0
  6. data/app/components/f_components/avatar/component.scss +3 -0
  7. data/app/components/f_components/base.rb +14 -0
  8. data/app/components/f_components/button/component.html.erb +5 -0
  9. data/app/components/f_components/button/component.rb +68 -0
  10. data/app/components/f_components/button/component.scss +9 -0
  11. data/app/components/f_components/collapsible/component.html.erb +6 -0
  12. data/app/components/f_components/collapsible/component.rb +15 -0
  13. data/app/components/f_components/collapsible/component.scss +19 -0
  14. data/app/components/f_components/dropdown/component.html.erb +10 -0
  15. data/app/components/f_components/dropdown/component.rb +19 -0
  16. data/app/components/f_components/dropdown/component.scss +10 -0
  17. data/app/components/f_components/form_field/component.html.erb +25 -0
  18. data/app/components/f_components/form_field/component.rb +124 -0
  19. data/app/components/f_components/resource_table/component.html.erb +17 -0
  20. data/app/components/f_components/resource_table/component.rb +139 -0
  21. data/app/components/f_components/table/component.html.erb +23 -0
  22. data/app/components/f_components/table/component.rb +88 -0
  23. data/app/components/f_components/table/component_controller.js +84 -0
  24. data/app/components/f_components/table/desktop/component.html.erb +25 -0
  25. data/app/components/f_components/table/desktop/component.rb +71 -0
  26. data/app/components/f_components/table/mobile/component.html.erb +8 -0
  27. data/app/components/f_components/table/mobile/component.rb +102 -0
  28. data/app/frontend/f_components/stylesheets/blocks/_button.scss +189 -0
  29. data/app/frontend/f_components/stylesheets/f_components.scss +12 -0
  30. data/app/frontend/f_components/stylesheets/variables/_breakpoints.scss +3 -0
  31. data/app/frontend/f_components/stylesheets/variables/_colors.scss +19 -0
  32. data/app/helpers/f_components/application_helper.rb +13 -0
  33. data/app/helpers/f_components/components_helper.rb +33 -0
  34. data/app/helpers/f_components/icons_helper.rb +34 -0
  35. data/config/webpack/development.js +5 -0
  36. data/config/webpack/environment.js +3 -0
  37. data/config/webpack/production.js +7 -0
  38. data/config/webpacker.yml +89 -0
  39. data/lib/f_components/engine.rb +28 -0
  40. data/lib/f_components/railtie.rb +12 -0
  41. data/lib/f_components/version.rb +5 -0
  42. data/lib/f_components.rb +18 -0
  43. metadata +158 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 23b88d28e2e9948702351020207b6aff6fddbd01e54e9f4ebfdb0532e08eee06
4
+ data.tar.gz: 90a0556f1bd62124ba52d0643cdd8274e6512f23e65bbabbdab239126f67d65c
5
+ SHA512:
6
+ metadata.gz: db56d7fc4a18a99bac2bc3d70b650f1eb49df41dfd4305de745fa3f285c13673ac14a482db220349eee6d2e7820f31d5fbc016b539946befd67235210f1c3568
7
+ data.tar.gz: 7a0d5d29de3e02f3ca7478477480fa65ea8ee68cc146d368a7e8d7f01fd3135bdba968e5846c1e340b328dc46ebfbfab6bf9d6c2fc31f56055fd3b8d0a06749f
data/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # FComponents
2
+
3
+ A library to share essential frontend components among applications.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'f_components', git: 'git@gitlab.com:fretadao/libs/f_components.git'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ This will allow the application to have access to view components classes and helpers.
20
+
21
+ Add this line to dependencies in your package.json file:
22
+
23
+ ```ruby
24
+ "f_components": "git+ssh://git@gitlab.com:fretadao/libs/f_components.git",
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ ```bash
30
+ $ yarn
31
+ ```
32
+
33
+ This will allow the application to apply the packed stylesheets and JavaScript from the library into your application. It's up to you chose whether it is convenient to be imported by sprockets or Webpacker.
34
+
35
+ ### Sprockets
36
+
37
+ #### Sass
38
+
39
+ If you're using sprockets as the main asset packing system, you may create a file sass with the following configurations:
40
+
41
+ `app/assets/stylesheets/f_components.scss`:
42
+
43
+ ```scss
44
+ $fc-clr-primary: <app primary color>;
45
+ $fc-clr-primary--dk: <app primary color dark>;
46
+ $fc-clr-secondary: <app secondary color>;
47
+ $fc-clr-secondary--dk: <app secondary color dark>;
48
+
49
+ $fc-clr-text: <app primary text color>;
50
+ $fc-clr-text-secondary: <app secondary text color>;
51
+
52
+ $fc-clr-success: <app success color>;
53
+ $fc-clr-warning: <app warning color>;
54
+ $fc-clr-error: <app error color>;
55
+
56
+ $fc-clr-disabled: <app disabled color>;
57
+ $fc-clr-border: <app border color>;
58
+
59
+ $fc-clr-background: <app background color>;
60
+
61
+ @import 'f_components/app/frontend/f_components/stylesheets/f_components';
62
+ ```
63
+
64
+ After creating the file you may import it in your `app/assets/stylesheets/application.scss` :
65
+
66
+ ```scss
67
+ @import 'f_components';
68
+ ```
69
+
70
+ ### Webpacker
71
+
72
+ #### Sass
73
+
74
+ If you're using webpacker as the main asset packing system, you may create a file sass with the following configurations:
75
+
76
+ `app/javascripts/stylesheets/f_components.scss`:
77
+
78
+ ```scss
79
+ $fc-clr-primary: <app-primary-color>;
80
+ $fc-clr-primary--dk: <app-primary-color-dark>;
81
+ $fc-clr-secondary: <app-secondary-color>;
82
+ $fc-clr-secondary--dk: <app-secondary-color-dark>;
83
+
84
+ $fc-clr-text: <app-primary-text-color>;
85
+ $fc-clr-text-secondary: <app-secondary-text-color>;
86
+
87
+ $fc-clr-success: <app-success-color>;
88
+ $fc-clr-warning: <app-warning-color>;
89
+ $fc-clr-error: <app-error-color>;
90
+
91
+ $fc-clr-disabled: <app-disabled-color>;
92
+ $fc-clr-border: <app-border-color>;
93
+
94
+ $fc-clr-background: <app-background-color>;
95
+
96
+ @import 'f_components/app/frontend/f_components/stylesheets/f_components';
97
+ ```
98
+
99
+ After creating the file you may import it in your `app/javascripts/packs/application.js` :
100
+
101
+ ```javascript
102
+ import '../stylesheets/f_components';
103
+ ```
104
+
105
+ Some components have Stimulus controllers, so you'll have to import them too:
106
+
107
+ ```javascript
108
+ import {Application} from 'stimulus';
109
+ import {TableComponentController} from 'f_components'; // Import controllers
110
+
111
+ const application = Application.start();
112
+
113
+ // Register the controllers. Please, keep the same naming. Otherwise, components won't work!
114
+ application.register('f-table-component', TableComponentController);
115
+
116
+ export {application};
117
+ ```
118
+
119
+ ## Development
120
+
121
+ ### Previews
122
+
123
+ To preview components access the dummy app:
124
+
125
+ ```bash
126
+ $ cd fretadao
127
+ ```
128
+
129
+ Run the servers (using docker):
130
+
131
+ ```bash
132
+ $ rake docker:dev:f_components
133
+ ```
134
+
135
+ Run the tests (using docker):
136
+
137
+ ```bash
138
+ $ rake docker:bash:f_components
139
+
140
+ # inside the container:
141
+ $ rspec
142
+ ```
143
+
144
+ Now just access `localhost:3030/previews` and see the components.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
6
+ load 'rails/tasks/engine.rake'
7
+
8
+ load 'rails/tasks/statistics.rake'
9
+
10
+ require 'bundler/gem_tasks'
11
+
12
+ require 'rake/testtask'
13
+
14
+ Rake::TestTask.new(:test) do |t|
15
+ t.libs << 'test'
16
+ t.pattern = 'test/**/*_test.rb'
17
+ t.verbose = false
18
+ end
19
+
20
+ task default: :test
@@ -0,0 +1 @@
1
+ <%= tag.img(src: image_url, class: class_names('Avatar', @class), loading: :lazy, width: size, height: size) %>
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FComponents
4
+ module Avatar
5
+ class Component < Base
6
+ def initialize(opts = {})
7
+ @class = opts.delete(:class) { '' }
8
+ @opts = opts
9
+ end
10
+
11
+ private
12
+
13
+ def image_url
14
+ "https://ui-avatars.com/api/?#{params}"
15
+ end
16
+
17
+ def params
18
+ default_options.merge(@opts).to_query
19
+ end
20
+
21
+ def size
22
+ @opts.fetch(:size, 64)
23
+ end
24
+
25
+ def default_options
26
+ { bold: true }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ .Avatar {
2
+ border-radius: 9999px;
3
+ }
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FComponents
4
+ class Base < ViewComponent::Base
5
+ extend FSupport::Attributes
6
+ include ComponentsHelper
7
+
8
+ delegate :fa_icon, to: :helpers
9
+
10
+ def self.call(...)
11
+ new(...)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ <% if button_tag? %>
2
+ <%= button_tag(title, class: classes, **options) %>
3
+ <% else %>
4
+ <%= link_to(title, href, class: classes, **options) %>
5
+ <% end %>
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FComponents
4
+ module Button
5
+ class Component < FComponents::Base
6
+ TYPE_CLASSES = {
7
+ primary: 'bt--primary',
8
+ secondary: 'bt--primary bt--outlined',
9
+ tertiary: 'bt--tertiary',
10
+ custom: ''
11
+ }.freeze
12
+
13
+ MODIFIERS = {
14
+ success: 'bt--success',
15
+ secondary: 'bt--secondary',
16
+ error: 'bt--error',
17
+ white: 'bt--white',
18
+ warning: 'bt--warning',
19
+ fit: 'w--fit max-w--fit',
20
+ full: 'bt--full',
21
+ outlined: 'bt--outlined',
22
+ small: 'bt--smr',
23
+ large: 'bt--lg',
24
+ centered: 'mx--auto'
25
+ }.freeze
26
+
27
+ MODS = MODIFIERS.to_h.deep_dup
28
+ MODS.default_proc = proc { |_hash, key| "bt--#{key}" }
29
+
30
+ attr_reader :href, :options
31
+
32
+ def initialize(title, href = nil, **options)
33
+ @title = title
34
+ @href = href || 'javascript: void(0);'
35
+ @modifiers = options.delete(:mods)
36
+ @type = options.delete(:type) || :primary
37
+ @tag = options.delete(:tag) || :a
38
+ @class = options.delete(:class) || ''
39
+ @left_icon = options.delete(:left_icon)
40
+ @options = options
41
+ end
42
+
43
+ private
44
+
45
+ def button_tag?
46
+ @tag == :button
47
+ end
48
+
49
+ def title
50
+ @left_icon.present? ? fa_icon(@left_icon, class: 'bt-leftIcon', text: @title) : @title
51
+ end
52
+
53
+ def classes
54
+ "bt bt--round #{button_type_class} #{modifiers} #{@class}"
55
+ end
56
+
57
+ def button_type_class
58
+ raise 'Unkown button type' unless TYPE_CLASSES.has_key?(@type)
59
+
60
+ TYPE_CLASSES[@type]
61
+ end
62
+
63
+ def modifiers
64
+ MODS.values_at(*@modifiers).compact.join(' ')
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,9 @@
1
+ .bt {
2
+ &--full {
3
+ width: 100%;
4
+ }
5
+
6
+ &-leftIcon {
7
+ margin-right: 10px;
8
+ }
9
+ }
@@ -0,0 +1,6 @@
1
+ <details class="Collapsible p-5 <%= @class %>">
2
+ <summary class="flex justify-between items-center cursor-pointer">
3
+ <%== formatted_summary %>
4
+ </summary>
5
+ <div><%= content %></div>
6
+ </details>
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FComponents
4
+ module Collapsible
5
+ class Component < Base
6
+ attributes :summary, class: nil
7
+
8
+ private
9
+
10
+ def formatted_summary
11
+ tag.div(class: 'flex space-x-5 justify-start items-center max-w-full') { summary }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ .Collapsible > summary {
2
+ list-style-type: none;
3
+ }
4
+
5
+ .Collapsible > summary::-webkit-details-marker {
6
+ display: none;
7
+ }
8
+
9
+ .Collapsible > summary::after {
10
+ font-family: "Font Awesome 5 Free";
11
+ font-weight: 900;
12
+ content: "\f078";
13
+ }
14
+
15
+ .Collapsible[open] > summary::after {
16
+ font-family: "Font Awesome 5 Free";
17
+ font-weight: 900;
18
+ content: "\f077";
19
+ }
@@ -0,0 +1,10 @@
1
+ <details class="Dropdown h-10 w-full bg-white rounded border-2 border-gray-lt open:border-primary <%= @class %>">
2
+ <summary class="Dropdown-label px-5 h-full flex items-center cursor-pointer <%= @label_class %>">
3
+ <%= icon %>
4
+ <%= label %>
5
+ </summary>
6
+
7
+ <div class="relative shadow-md rounded bg-white z-10 mt-1 md:inset-auto <%= padding_class %> <%= content_class %>">
8
+ <%= content %>
9
+ </div>
10
+ </details>
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FComponents
4
+ module Dropdown
5
+ class Component < Base
6
+ attributes :label, icon: nil, class: nil, label_class: nil, content_class: nil, padding: true
7
+
8
+ private
9
+
10
+ def icon
11
+ @icon ? fa_icon(@icon, class: 'mr-5') : nil
12
+ end
13
+
14
+ def padding_class
15
+ 'p-5' if padding
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ .Dropdown {
2
+ &-label {
3
+ list-style: none;
4
+
5
+ &::marker {
6
+ display: none;
7
+ }
8
+ }
9
+ }
10
+
@@ -0,0 +1,25 @@
1
+ <%= tag.div(**container_options) do %>
2
+ <% if label? %>
3
+ <%= form.label @attribute_name, sanitize(label_options.delete(:text)), class: label_options[:class] %>
4
+ <% end %>
5
+ <% if icon? %>
6
+ <%= fa_icon icon_position_options[:icon], **icon_position_options.except(:icon) %>
7
+ <% end %>
8
+ <% if select_field? %>
9
+ <%=
10
+ form.select(
11
+ @attribute_name,
12
+ options_for_select(select_options[:collection], select_options[:selected]),
13
+ select_options.except(:collection, :selected),
14
+ **field_options
15
+ )
16
+ %>
17
+ <% else %>
18
+ <%= form.text_field @attribute_name, **field_options %>
19
+ <% end %>
20
+ <% if field_with_error? %>
21
+ <% field_errors.each do |field_error| %>
22
+ <span class="Form-errorMessage"><%= field_error %></span>
23
+ <% end %>
24
+ <% end %>
25
+ <% end %>
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FComponents
4
+ module FormField
5
+ class Component < Base
6
+ attr_reader :attribute_name, :options, :form
7
+
8
+ def initialize(form, attribute_name, **options)
9
+ @form = form
10
+ @attribute_name = attribute_name
11
+ @options = options
12
+
13
+ define_elements_classes
14
+ end
15
+
16
+ private
17
+
18
+ def define_elements_classes
19
+ define_container_classes
20
+ define_label_classes
21
+ define_field_classes
22
+ define_icon_classes
23
+ end
24
+
25
+ def define_container_classes
26
+ container_classes = %w[Form-inputGroup w-full]
27
+ container_classes << container_options[:class]
28
+
29
+ container_options[:class] = container_classes.compact.join(' ')
30
+ end
31
+
32
+ def define_label_classes
33
+ label_classes = %w[Form-label w-full]
34
+ label_classes << label_options[:class]
35
+
36
+ label_options[:class] = label_classes.compact.join(' ')
37
+ end
38
+
39
+ def define_field_classes
40
+ field_classes = %w[Form-input w-full]
41
+
42
+ field_classes << input_icon_position_class if icon?
43
+ field_classes << 'Form-input--error' if field_with_error?
44
+ field_classes << field_options[:class]
45
+
46
+ field_options[:class] = field_classes.compact.join(' ')
47
+ end
48
+
49
+ def define_icon_classes
50
+ return unless icon?
51
+
52
+ icon_classes = ['Form-icon', icon_position_class, icon_position_options[:class]]
53
+
54
+ icon_position_options[:class] = icon_classes.compact.join(' ')
55
+ end
56
+
57
+ def icon_position_options
58
+ return @icon_position_options if defined? @icon_position_options
59
+
60
+ @icon_position_options = icon_options[:leading_icon] || icon_options[:trailing_icon]
61
+ end
62
+
63
+ def container_options
64
+ @container_options ||= options[:container_options].to_h
65
+ end
66
+
67
+ def label_options
68
+ @label_options ||= options[:label_options].to_h
69
+ end
70
+
71
+ def field_options
72
+ @field_options ||= options[:field_options].to_h
73
+ end
74
+
75
+ def icon_options
76
+ @icon_options ||= options[:icon_options].to_h
77
+ end
78
+
79
+ def select_options
80
+ return @select_options if defined?(@select_options)
81
+
82
+ @select_options = field_options.delete(:select_options).to_h
83
+ end
84
+
85
+ def field_errors
86
+ return [] if @form.object.nil?
87
+
88
+ @field_errors = @form.object.errors[@attribute_name]
89
+ end
90
+
91
+ def input_icon_position_class
92
+ leading_icon? ? 'Form-input--withLeftIcon' : 'Form-input--withRightIcon'
93
+ end
94
+
95
+ def icon_position_class
96
+ leading_icon? ? 'Form-iconLeft' : 'Form-iconRight'
97
+ end
98
+
99
+ def icon?
100
+ icon_position_options.present?
101
+ end
102
+
103
+ def label?
104
+ label_options[:text] != false
105
+ end
106
+
107
+ def leading_icon?
108
+ icon_options[:leading_icon].present?
109
+ end
110
+
111
+ def trailing_icon?
112
+ icon_options[:trailing_icon].present?
113
+ end
114
+
115
+ def field_with_error?
116
+ field_errors.any?
117
+ end
118
+
119
+ def select_field?
120
+ select_options.present?
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,17 @@
1
+ <table class="w-full hidden <%= table_layout %> <%= @class %>">
2
+ <%= table_header %>
3
+ <tbody class="text-sm">
4
+ <% resources.each do |resource| %>
5
+ <%= table_row(resource, class: 'even:bg-gray-ltr') %>
6
+ <% end %>
7
+ </tbody>
8
+ </table>
9
+
10
+ <div class="md:hidden <%= @class %>">
11
+ <% resources.each_with_index do |resource| %>
12
+ <%= mobile_header(resource, class: 'bg-white border-b border-gray-lt') do %>
13
+ <%= mobile_rows(resource, class: 'flex flex-col space-y-5 mt-5') %>
14
+ <%= link_to_resource(resource, display_as: :button) %>
15
+ <% end %>
16
+ <% end %>
17
+ </div>