alveole 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.gitlab-ci.yml +55 -0
  4. data/.rubocop.yml +63 -0
  5. data/.rubocop_todo.yml +12 -0
  6. data/.travis.yml +6 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +7 -0
  9. data/Gemfile.lock +171 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +44 -0
  12. data/Rakefile +10 -0
  13. data/alveole.gemspec +35 -0
  14. data/bin/console +14 -0
  15. data/bin/setup +8 -0
  16. data/lib/alveole/components/avatar_component/avatar_component.html.slim +6 -0
  17. data/lib/alveole/components/avatar_component.rb +9 -0
  18. data/lib/alveole/components/badge_component/badge_component.html.slim +2 -0
  19. data/lib/alveole/components/badge_component.rb +8 -0
  20. data/lib/alveole/components/breadcrumb_component/breadcrumb_component.html.slim +2 -0
  21. data/lib/alveole/components/breadcrumb_component.rb +8 -0
  22. data/lib/alveole/components/breadcrumbs_component.rb +7 -0
  23. data/lib/alveole/components/button_component/button_component.html.slim +5 -0
  24. data/lib/alveole/components/button_component.rb +15 -0
  25. data/lib/alveole/components/definition_component/definition_component.html.slim +4 -0
  26. data/lib/alveole/components/definition_component.rb +13 -0
  27. data/lib/alveole/components/form_component/form_component.html.slim +3 -0
  28. data/lib/alveole/components/form_component.rb +3 -0
  29. data/lib/alveole/components/form_submit_component/form_submit_component.html.slim +1 -0
  30. data/lib/alveole/components/form_submit_component.rb +7 -0
  31. data/lib/alveole/components/heading_component/heading_component.html.slim +4 -0
  32. data/lib/alveole/components/heading_component.rb +8 -0
  33. data/lib/alveole/components/input_component/input_component.html.slim +17 -0
  34. data/lib/alveole/components/input_component.rb +42 -0
  35. data/lib/alveole/components/notice_component/notice_component.html.slim +5 -0
  36. data/lib/alveole/components/notice_component.rb +15 -0
  37. data/lib/alveole/components/page_component/page_component.html.slim +10 -0
  38. data/lib/alveole/components/page_component.rb +4 -0
  39. data/lib/alveole/components/sidebar_component/sidebar_component.html.slim +7 -0
  40. data/lib/alveole/components/sidebar_component.rb +4 -0
  41. data/lib/alveole/components/table_column_component/table_column_component.html.slim +3 -0
  42. data/lib/alveole/components/table_column_component.rb +12 -0
  43. data/lib/alveole/components/table_component/table_component.html.slim +7 -0
  44. data/lib/alveole/components/table_component.rb +3 -0
  45. data/lib/alveole/components/table_header_component/table_header_component.html.slim +2 -0
  46. data/lib/alveole/components/table_header_component.rb +8 -0
  47. data/lib/alveole/components/table_row_component/table_row_component.html.slim +4 -0
  48. data/lib/alveole/components/table_row_component.rb +3 -0
  49. data/lib/alveole/components/toolbar_component/toolbar_component.html.slim +7 -0
  50. data/lib/alveole/components/toolbar_component.rb +4 -0
  51. data/lib/alveole/concerns/bem.rb +21 -0
  52. data/lib/alveole/engine.rb +30 -0
  53. data/lib/alveole/helpers/method_helper.rb +31 -0
  54. data/lib/alveole/javascript/components.js +5 -0
  55. data/lib/alveole/previews/avatar_component_preview.rb +11 -0
  56. data/lib/alveole/previews/badge_component_preview.rb +11 -0
  57. data/lib/alveole/previews/breadcrumb_component_preview.rb +15 -0
  58. data/lib/alveole/previews/button_component_preview.rb +7 -0
  59. data/lib/alveole/previews/definition_component_preview.rb +33 -0
  60. data/lib/alveole/previews/form_component_preview.rb +18 -0
  61. data/lib/alveole/previews/form_submit_component_preview.rb +7 -0
  62. data/lib/alveole/previews/heading_component_preview.rb +11 -0
  63. data/lib/alveole/previews/input_component_preview.rb +32 -0
  64. data/lib/alveole/previews/notice_component_preview.rb +15 -0
  65. data/lib/alveole/previews/page_component_preview.rb +33 -0
  66. data/lib/alveole/previews/sidebar_component_preview.rb +33 -0
  67. data/lib/alveole/previews/table_column_component_preview.rb +36 -0
  68. data/lib/alveole/previews/table_component_preview.rb +12 -0
  69. data/lib/alveole/previews/table_header_component_preview.rb +27 -0
  70. data/lib/alveole/previews/table_row_component_preview.rb +18 -0
  71. data/lib/alveole/previews/toolbar_component_preview.rb +33 -0
  72. data/lib/alveole/version.rb +3 -0
  73. data/lib/alveole.rb +16 -0
  74. data/lib/generators/alveole/config_generator.rb +17 -0
  75. data/lib/generators/alveole/templates/alveole_config.rb +1 -0
  76. metadata +197 -0
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task default: :test
data/alveole.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ require_relative 'lib/alveole/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'alveole'
5
+ spec.version = Alveole::VERSION
6
+ spec.authors = ['Marine Sourin', 'Marine Domine', 'Cedric Feyaerts', 'Thomas Kienlen']
7
+ spec.email = ['marinesourin@live.fr', 'marine@captive.fr', 'c.feyaerts@captive.fr', 't.kienlen@captive.fr']
8
+
9
+ spec.summary = 'Components and generator for the Alveole design system'
10
+ spec.homepage = 'https://git.captive.fr' # TODO: fix this
11
+ spec.license = 'MIT'
12
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
13
+
14
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
15
+
16
+ spec.metadata['homepage_uri'] = spec.homepage
17
+ spec.metadata['source_code_uri'] = 'https://git.captive.fr' # TODO: fix this
18
+ spec.metadata['changelog_uri'] = 'https://git.captive.fr' # TODO: fix this
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = 'exe'
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ['lib']
28
+
29
+ spec.add_dependency 'actionview'
30
+ spec.add_dependency 'activesupport', '>= 4.1.0'
31
+ spec.add_dependency 'rails'
32
+ spec.add_dependency 'view_component', '~> 2.35'
33
+
34
+ spec.add_development_dependency 'rubocop', '~> 1.18'
35
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'alveole'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,6 @@
1
+ .avatar *@options
2
+ - if @url
3
+ = link_to(@url)
4
+ .avatar__content style="background-image: url(#{@image})"
5
+ - else
6
+ .avatar__content style="background-image: url(#{@image})"
@@ -0,0 +1,9 @@
1
+ class AvatarComponent < ViewComponent::Base
2
+ def initialize(image:, url: nil, options: {})
3
+ super
4
+
5
+ @image = image
6
+ @url = url
7
+ @options = options
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ .badge *@options
2
+ = @label
@@ -0,0 +1,8 @@
1
+ class BadgeComponent < ViewComponent::Base
2
+ def initialize(label:, options: {})
3
+ super
4
+
5
+ @label = label
6
+ @options = options
7
+ end
8
+ end
@@ -0,0 +1,2 @@
1
+ span.breadcrumb
2
+ = link_to_if @url, @label, @url, class: 'breadcrumb__link'
@@ -0,0 +1,8 @@
1
+ class BreadcrumbComponent < ViewComponent::Base
2
+ def initialize(label:, url: nil)
3
+ super
4
+
5
+ @url = url
6
+ @label = label
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ class BreadcrumbsComponent < ViewComponent::Base
2
+ def call
3
+ tag.div(class: 'breadcrumbs') do
4
+ content
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ = link_to @url, @options.merge(class: ['button'] + @bem_classes) do
2
+ - if @icon
3
+ i.button__icon { class=@icon }
4
+ - unless @modifiers.include? :icon_only
5
+ span.button__label = @label
@@ -0,0 +1,15 @@
1
+ class ButtonComponent < ViewComponent::Base
2
+ include Alveole::Concerns::Bem
3
+
4
+ MODIFIERS = %i[small icon_only primary].freeze
5
+
6
+ def initialize(url:, label:, icon: nil, modifiers: [], options: {})
7
+ super
8
+
9
+ @url = url
10
+ @label = label
11
+ @icon = icon
12
+ @options = options
13
+ self.modifiers = modifiers
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ dl.definition
2
+ dt.definition__label = @label
3
+ dd.definition__value *@options
4
+ = content || @value
@@ -0,0 +1,13 @@
1
+ class DefinitionComponent < ViewComponent::Base
2
+ def initialize(label: nil, value: nil, obj: nil, fieldname: nil, options: {})
3
+ super
4
+
5
+ @obj = obj
6
+ @fieldname = fieldname
7
+ @value = value || obj&.send(fieldname)
8
+ @value = ApplicationController.helpers.format_value(@value, options)
9
+ @value = '---' if @value.blank?
10
+ @label = label || ApplicationController.helpers.label_for(obj, fieldname)
11
+ @options = options
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ .form
2
+ fieldset.form__inputs = content
3
+ fieldset.form__actions = actions
@@ -0,0 +1,3 @@
1
+ class FormComponent < ViewComponent::Base
2
+ renders_one :actions
3
+ end
@@ -0,0 +1 @@
1
+ input[type="submit" name="commit" value=@label class='form__action button button--primary']
@@ -0,0 +1,7 @@
1
+ class FormSubmitComponent < ViewComponent::Base
2
+ def initialize(label:)
3
+ super
4
+
5
+ @label = label
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ h1.heading
2
+ = @heading
3
+ = content
4
+ h2.heading--sub = @sub
@@ -0,0 +1,8 @@
1
+ class HeadingComponent < ViewComponent::Base
2
+ def initialize(heading: nil, sub: nil)
3
+ super
4
+
5
+ @heading = heading
6
+ @sub = sub
7
+ end
8
+ end
@@ -0,0 +1,17 @@
1
+ .input class=@bem_classes
2
+ = @form.label @fieldname, @label, class: 'input__label'
3
+ - case @type
4
+ - when :text
5
+ = @form.text_field @fieldname, @options.merge(class: 'input__input')
6
+ - when :date
7
+ = @form.text_field @fieldname, @options.merge(class: 'input__input datepicker')
8
+ - when :color
9
+ = @form.color_field @fieldname, @options
10
+ - when :select
11
+ = @form.select @fieldname, @collection, @options, @options.merge(class: 'input__input')
12
+ - when :file
13
+ = @form.file_field @fieldname, @options.merge(class: 'input__input')
14
+ - when :text_area
15
+ = @form.text_area @fieldname, @options.merge(class: 'input__input')
16
+ - if @error_message
17
+ .input__errors = @error_message
@@ -0,0 +1,42 @@
1
+ class InputComponent < ViewComponent::Base
2
+ include Alveole::Concerns::Bem
3
+
4
+ MODIFIERS = %i[disabled error].freeze
5
+
6
+ def initialize(type: nil, label: nil,
7
+ value: nil,
8
+ form: nil,
9
+ fieldname: nil,
10
+ collection: nil,
11
+ modifiers: [],
12
+ options: {})
13
+ super
14
+
15
+ @label = label
16
+ @form = form
17
+ @fieldname = fieldname
18
+ @collection = collection
19
+ @options = options
20
+ @options[:value] = value if value
21
+ @type = type || :text
22
+ @error_message = error_message
23
+
24
+ modifiers << :error if error?
25
+ modifiers << :disabled if options[:disabled]
26
+ self.modifiers = modifiers
27
+ end
28
+
29
+ private
30
+
31
+ def error?
32
+ return false unless @form.object.respond_to? :errors
33
+
34
+ @error ||= @form.object.errors.include?(@fieldname.to_s.sub(/_id$/, ''))
35
+ end
36
+
37
+ def error_message
38
+ return unless error?
39
+
40
+ @error_message ||= @form.object.errors.messages_for(@fieldname.to_s.sub(/_id$/, '')).join(', ')
41
+ end
42
+ end
@@ -0,0 +1,5 @@
1
+ .notice class="notice--#{@type}"
2
+ .notice__title = @title
3
+ ul.notice__messages
4
+ - @messages.each do |message|
5
+ .notice__message = message
@@ -0,0 +1,15 @@
1
+ class NoticeComponent < ViewComponent::Base
2
+ TYPES = %w[notice alert].freeze
3
+ def initialize(title:, messages: [], type: nil)
4
+ super
5
+
6
+ @type = type if TYPES.include?(type)
7
+ @type ||= 'alert'
8
+ @title = title
9
+ @messages = messages
10
+ end
11
+
12
+ def render?
13
+ @messages.any?
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ .page
2
+ .page__header_wrapper
3
+ .page__header
4
+ = header
5
+ .page__content_wrapper
6
+ .page__content
7
+ = content
8
+ .page__actions_wrapper
9
+ .page__actions
10
+ = actions
@@ -0,0 +1,4 @@
1
+ class PageComponent < ViewComponent::Base
2
+ renders_one :actions
3
+ renders_one :header
4
+ end
@@ -0,0 +1,7 @@
1
+ aside.sidebar
2
+ section.sidebar__start
3
+ = top
4
+ section.sidebar__middle
5
+ = content
6
+ section.sidebar__end
7
+ = bottom
@@ -0,0 +1,4 @@
1
+ class SidebarComponent < ViewComponent::Base
2
+ renders_one :top
3
+ renders_one :bottom
4
+ end
@@ -0,0 +1,3 @@
1
+ td.table__column
2
+ = link_to_if @url, @value, @url
3
+ = content
@@ -0,0 +1,12 @@
1
+ class TableColumnComponent < ViewComponent::Base
2
+ def initialize(value: nil, obj: nil, fieldname: nil, url: nil, options: {})
3
+ super
4
+
5
+ @obj = obj
6
+ @fieldname = fieldname
7
+ @value = value || obj&.send(fieldname)
8
+ @value = ApplicationController.helpers.format_value(@value, options)
9
+ @url = url
10
+ @options = options
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ table.table
2
+ thead
3
+ tr
4
+ = headers
5
+ th
6
+ tbody
7
+ = content
@@ -0,0 +1,3 @@
1
+ class TableComponent < ViewComponent::Base
2
+ renders_one :headers
3
+ end
@@ -0,0 +1,2 @@
1
+ th.table__header
2
+ = link_to_if @url, @label, @url
@@ -0,0 +1,8 @@
1
+ class TableHeaderComponent < ViewComponent::Base
2
+ def initialize(label: nil, url: nil, obj: nil, fieldname: nil)
3
+ super
4
+
5
+ @label = label || ApplicationController.helpers.label_for(obj, fieldname)
6
+ @url = url
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ tr.table__row
2
+ = content
3
+ td.table__column
4
+ = actions
@@ -0,0 +1,3 @@
1
+ class TableRowComponent < ViewComponent::Base
2
+ renders_one :actions
3
+ end
@@ -0,0 +1,7 @@
1
+ .toolbar
2
+ section.toolbar__start
3
+ = left
4
+ section.toolbar__middle
5
+ = content
6
+ section.toolbar__end
7
+ = right
@@ -0,0 +1,4 @@
1
+ class ToolbarComponent < ViewComponent::Base
2
+ renders_one :left
3
+ renders_one :right
4
+ end
@@ -0,0 +1,21 @@
1
+ module Alveole
2
+ module Concerns
3
+ module Bem
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ const_set('COMPONENT_NAME', name.gsub('Component', '').underscore.dasherize)
8
+ const_set('MODIFIERS', [])
9
+ end
10
+
11
+ def modifiers=(values)
12
+ @bem_classes ||= []
13
+ @modifiers = values & self.class::MODIFIERS
14
+
15
+ @modifiers.each do |modifier|
16
+ @bem_classes << "#{self.class::COMPONENT_NAME}--#{modifier.to_s.dasherize}"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ require 'rails/engine'
2
+ require 'view_component/engine'
3
+
4
+ module Alveole
5
+ # :nodoc:
6
+ class Engine < ::Rails::Engine
7
+ # isolate_namespace Primer::ViewComponents
8
+
9
+ config.autoload_once_paths = %W[
10
+ #{root}/lib/alveole/concerns
11
+ #{root}/lib/alveole/components
12
+ #{root}/lib/alveole/helpers
13
+ #{root}/lib/alveole/javascript
14
+ #{root}/lib/generators/
15
+ ]
16
+
17
+ config.view_component.preview_paths << "#{Engine.root}/lib/alveole/previews"
18
+ config.view_component.show_previews_source = true
19
+
20
+ # config.primer_view_components = ActiveSupport::OrderedOptions.new
21
+
22
+ # config.primer_view_components.force_functional_colors = true
23
+ # config.primer_view_components.force_system_arguments = false
24
+ # config.primer_view_components.silence_deprecations = false
25
+
26
+ # initializer "primer_view_components.assets" do |app|
27
+ # app.config.assets.precompile += %w[primer_view_components] if app.config.respond_to?(:assets)
28
+ # end
29
+ end
30
+ end