dsfr-view-components 0.0.1

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.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +214 -0
  3. data/Rakefile +22 -0
  4. data/app/components/dsfr_component/accordion_component/section_component.html.erb +11 -0
  5. data/app/components/dsfr_component/accordion_component/section_component.rb +39 -0
  6. data/app/components/dsfr_component/accordion_component.html.erb +5 -0
  7. data/app/components/dsfr_component/accordion_component.rb +33 -0
  8. data/app/components/dsfr_component/alert_component.rb +22 -0
  9. data/app/components/dsfr_component/back_link_component.rb +24 -0
  10. data/app/components/dsfr_component/base.rb +28 -0
  11. data/app/components/dsfr_component/breadcrumbs_component.html.erb +7 -0
  12. data/app/components/dsfr_component/breadcrumbs_component.rb +51 -0
  13. data/app/components/dsfr_component/cookie_banner_component/message_component.rb +62 -0
  14. data/app/components/dsfr_component/cookie_banner_component.rb +35 -0
  15. data/app/components/dsfr_component/details_component.rb +42 -0
  16. data/app/components/dsfr_component/footer_component.html.erb +49 -0
  17. data/app/components/dsfr_component/footer_component.rb +87 -0
  18. data/app/components/dsfr_component/header_component.html.erb +51 -0
  19. data/app/components/dsfr_component/header_component.rb +145 -0
  20. data/app/components/dsfr_component/inset_text_component.rb +28 -0
  21. data/app/components/dsfr_component/notification_banner_component.html.erb +14 -0
  22. data/app/components/dsfr_component/notification_banner_component.rb +93 -0
  23. data/app/components/dsfr_component/pagination_component/adjacent_page.rb +59 -0
  24. data/app/components/dsfr_component/pagination_component/item.rb +77 -0
  25. data/app/components/dsfr_component/pagination_component/next_page.rb +27 -0
  26. data/app/components/dsfr_component/pagination_component/previous_page.rb +21 -0
  27. data/app/components/dsfr_component/pagination_component.rb +129 -0
  28. data/app/components/dsfr_component/panel_component.rb +56 -0
  29. data/app/components/dsfr_component/phase_banner_component.html.erb +6 -0
  30. data/app/components/dsfr_component/phase_banner_component.rb +25 -0
  31. data/app/components/dsfr_component/section_break_component.rb +49 -0
  32. data/app/components/dsfr_component/start_button_component.rb +55 -0
  33. data/app/components/dsfr_component/summary_list_component/action_component.rb +42 -0
  34. data/app/components/dsfr_component/summary_list_component/key_component.rb +23 -0
  35. data/app/components/dsfr_component/summary_list_component/row_component.rb +57 -0
  36. data/app/components/dsfr_component/summary_list_component/value_component.rb +23 -0
  37. data/app/components/dsfr_component/summary_list_component.html.erb +5 -0
  38. data/app/components/dsfr_component/summary_list_component.rb +49 -0
  39. data/app/components/dsfr_component/tab_component.html.erb +11 -0
  40. data/app/components/dsfr_component/tab_component.rb +61 -0
  41. data/app/components/dsfr_component/table_component/body_component.html.erb +5 -0
  42. data/app/components/dsfr_component/table_component/body_component.rb +21 -0
  43. data/app/components/dsfr_component/table_component/caption_component.rb +37 -0
  44. data/app/components/dsfr_component/table_component/cell_component.rb +57 -0
  45. data/app/components/dsfr_component/table_component/head_component.html.erb +5 -0
  46. data/app/components/dsfr_component/table_component/head_component.rb +23 -0
  47. data/app/components/dsfr_component/table_component/row_component.html.erb +5 -0
  48. data/app/components/dsfr_component/table_component/row_component.rb +30 -0
  49. data/app/components/dsfr_component/table_component.html.erb +7 -0
  50. data/app/components/dsfr_component/table_component.rb +35 -0
  51. data/app/components/dsfr_component/tag_component.rb +44 -0
  52. data/app/components/dsfr_component/traits/custom_html_attributes.rb +7 -0
  53. data/app/components/dsfr_component/traits.rb +1 -0
  54. data/app/components/dsfr_component/warning_text_component.rb +37 -0
  55. data/app/components/dsfr_component.rb +1 -0
  56. data/app/helpers/dsfr_back_to_top_link_helper.rb +14 -0
  57. data/app/helpers/dsfr_components_helper.rb +33 -0
  58. data/app/helpers/dsfr_link_helper.rb +123 -0
  59. data/app/helpers/dsfr_skip_link_helper.rb +13 -0
  60. data/config/routes.rb +2 -0
  61. data/lib/dsfr/components/engine.rb +110 -0
  62. data/lib/dsfr/components/helpers/css_utilities.rb +22 -0
  63. data/lib/dsfr/components/version.rb +5 -0
  64. data/lib/dsfr/components.rb +6 -0
  65. data/lib/tasks/dsfr/components_tasks.rake +4 -0
  66. metadata +482 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 13a375b911fee2a88bc620482b766be2d3348d0138d56f9f2cb2641f649e8d50
4
+ data.tar.gz: 85f677a71346315a8c128f156b32c74b6436528bfa5ed98fcaf490d352fdeb71
5
+ SHA512:
6
+ metadata.gz: 6b10dd868701e33699626fa4753fd7a017128f87b91394c72100d24b014c16206e5285ca81778d045c025241c56a6a97805859b6af75d1c946ba917677818dc7
7
+ data.tar.gz: e81ae1788e01bc3e24ec2cc07a4ccfd2cf8fef13fd6d6a5a865423cdf584d65a5303c0965681ff2a922e2cb50bc61bbffb3eca87f20c7cf4224bbd51a355ee06
data/README.md ADDED
@@ -0,0 +1,214 @@
1
+ # Composants du DSFR
2
+
3
+ Cette gem fournit des composants pour le Design Système de l'État (DSFR) en s'appuyant sur le [framework ViewComponent](https://github.com/ViewComponent/view_component).
4
+
5
+ C'est un fork de [govuk-components](https://github.com/DFE-Digital/govuk-components) qui propose l'équivalent pour le GOV.UK Design System.
6
+
7
+ ⚠️ Cette gem est en cours de développement et n'est pas adaptée à un usage en production. N'hésitez pas à contribuer pour nous aider à avancer !
8
+
9
+ [![Tests](https://github.com/betagouv/dsfr-view-components/workflows/Tests/badge.svg)](https://github.com/betagouv/dsfr-view-components/actions?query=workflow%3ATests)
10
+
11
+ <!--
12
+ [![Maintainability](https://api.codeclimate.com/v1/badges/cbcbc140f300b920d833/maintainability)](https://codeclimate.com/github/DFE-Digital/govuk-components/maintainability)
13
+ [![Gem Version](https://badge.fury.io/rb/govuk-components.svg)](https://badge.fury.io/rb/govuk-components)
14
+ [![Gem](https://img.shields.io/gem/dt/govuk-components?logo=rubygems)](https://rubygems.org/gems/govuk-components)
15
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/cbcbc140f300b920d833/test_coverage)](https://codeclimate.com/github/DFE-Digital/govuk-components/test_coverage)
16
+ [![GitHub license](https://img.shields.io/github/license/DFE-Digital/govuk-components)](https://github.com/DFE-Digital/govuk-components/blob/main/LICENSE)
17
+ [![GOV.UK Design System Version](https://img.shields.io/badge/GOV.UK%20Design%20System-4.3.0-brightgreen)](https://design-system.service.gov.uk)
18
+ [![Rails](https://img.shields.io/badge/Rails-6.1.5%20%E2%95%B1%207.0.3-E16D6D)](https://weblog.rubyonrails.org/releases/)
19
+ [![Ruby](https://img.shields.io/badge/Ruby-2.7.6%20%20%E2%95%B1%203.0.3%20%20%E2%95%B1%203.1.2-E16D6D)](https://www.ruby-lang.org/en/downloads/)
20
+
21
+ This gem provides a suite of reusable components for the [GOV.UK Design System](https://design-system.service.gov.uk/). It is intended to provide a lightweight alternative to the [GOV.UK Publishing Components](https://github.com/alphagov/dsfr_publishing_components) library and is built with GitHub’s [ViewComponent](https://github.com/github/view_component) framework.
22
+
23
+ It aims to implement the functionality from the original Nunjucks macros in a way that will feel more familiar to Rails developers. Blocks are preferred over strings of HTML, beneath the surface each component is just a Ruby object, everything is inheritable and overrideable.
24
+
25
+ ## Documentation
26
+
27
+ The gem comes with [a full guide](https://govuk-components.netlify.app/) that
28
+ covers most aspects of day-to-day use, along with code and output examples. The
29
+ examples in the guide (and the guide itself) are built using the components,
30
+ so it will always be up to date.
31
+
32
+ [![Netlify Status](https://api.netlify.com/api/v1/badges/d40a5a0a-b086-4c35-b046-97fbcbf9f219/deploy-status)](https://app.netlify.com/sites/govuk-components/deploys)
33
+
34
+ -->
35
+
36
+ ## Composants disponibles
37
+
38
+ Cette gem a pour but de supporter tous les composants proposés par le Design Système de l'État hormis ceux concernant les formulaires. Ceux-ci seront fournis dans une gem indépendante dans le futur.
39
+
40
+ Les composants disponibles sont :
41
+
42
+ - [ ] Accordéon - Accordion
43
+ - [ ] Ajout de fichier - File upload
44
+ - [ ] Alertes - Alert
45
+ - [ ] Badge
46
+ - [ ] Bandeau d'information importante
47
+ - [ ] Barre de recherche - Search bar
48
+ - [ ] Boutons - Buttons
49
+ - [ ] Groupe de bouton
50
+ - [ ] Bouton FranceConnect
51
+ - [ ] Boutons radio
52
+ - [ ] Boutons radio 'riches'
53
+ - [ ] Case à cocher - Checkbox
54
+ - [ ] Cartes - Cards
55
+ - [ ] Champ de saisie - Input
56
+ - [ ] Citation - Quote
57
+ - [ ] Contenu médias - Responsive médias
58
+ - [ ] En-tête - Header
59
+ - [ ] Fil d'Ariane - Breadcrumb
60
+ - [ ] Gestionnaire de consentement - Consent banner
61
+ - [ ] Icônes de favoris - Favicons
62
+ - [ ] Indicateur d'étape
63
+ - [ ] Interrupteur - Toggle switch
64
+ - [ ] Lettre d'information et réseaux sociaux - Newsletter &amp; Follow us
65
+ - [ ] Liens - Links
66
+ - [ ] Liens d'évitement - Skiplinks
67
+ - [ ] Liste déroulante - Select
68
+ - [ ] Menu latéral - Side menu
69
+ - [ ] Mise en avant - Call out
70
+ - [ ] Mise en exergue - Highlight
71
+ - [ ] Modale - Modal
72
+ - [ ] Navigation principale - Main navigation
73
+ - [ ] Onglets - Tabs
74
+ - [ ] Pagination
75
+ - [ ] Paramètres d'affichage - Display
76
+ - [ ] Partage - Share
77
+ - [ ] Pied de page - Footer
78
+ - [ ] Sélecteur de langue
79
+ - [ ] Sommaire - Summary
80
+ - [ ] Tableau - Table
81
+ - [ ] Tag
82
+ - [ ] Téléchargement de fichier
83
+ - [ ] Tuile - Tile
84
+
85
+ <!--
86
+ This library also provides helpers for creating [links](https://govuk-components.netlify.app/helpers/link),
87
+ [buttons](https://govuk-components.netlify.app/helpers/button), [skip links](https://govuk-components.netlify.app/helpers/skip-link)
88
+ and [back to top links](https://govuk-components.netlify.app/helpers/back-to-top-link).
89
+ -->
90
+
91
+ <!--
92
+ ## Alternative syntax
93
+
94
+ All of the components can be rendered in two ways:
95
+
96
+ * directly using Rails’ `#render` method:
97
+
98
+ ```erb
99
+ <%= render DsfrComponent::WarningTextComponent.new do %>
100
+ A serious warning
101
+ <% end %>
102
+ ```
103
+
104
+ * via the helper wrapper:
105
+
106
+ ```erb
107
+ <%= dsfr_warning_text do %>
108
+ A serious warning
109
+ <% end %>
110
+ ```
111
+
112
+ The naming convention for helpers is `dsfr_` followed by the component’s name in snake case. You can see the full list in [DsfrComponentsHelper](app/helpers/dsfr_components_helper.rb).
113
+
114
+ ## Example use
115
+
116
+ This library allows components to be rendered with Rails’ `render` method or via the provided helpers. Here we’ll use the `dsfr_tabs` to render three tabbed sections:
117
+
118
+ ```erb
119
+ <%= dsfr_tabs(title: 'Days of the week') do |component| %>
120
+ <% component.tab(label: 'Monday') do %>
121
+ <p>Monday’s child is fair of face</p>
122
+ <% end %>
123
+
124
+ <% component.tab(label: 'Tuesday') do %>
125
+ <p>Tuesday’s child is full of grace</p>
126
+ <% end %>
127
+
128
+ <% component.tab(label: 'Wednesday') do %>
129
+ <p>Wednesday’s child is full of woe</p>
130
+ <% end %>
131
+ <% end %>
132
+ ```
133
+
134
+ Here are the rendered tabs:
135
+
136
+ ![Tabs preview](docs/images/tabs.png)
137
+
138
+ For examples on usage see the [guide page](https://govuk-components.netlify.app/).
139
+
140
+ ## Setup
141
+
142
+ Add this line to your `config/application.rb`:
143
+
144
+ ```ruby
145
+ require "govuk/components"
146
+ ```
147
+
148
+ ## Services using this library
149
+
150
+ * [Apply for teacher training](https://github.com/DFE-Digital/apply-for-teacher-training)
151
+ * [Find postgraduate teacher training](https://github.com/DFE-Digital/find-teacher-training)
152
+ * [Get help with technology](https://github.com/DFE-Digital/get-help-with-tech)
153
+ * [Publish teacher training courses](https://github.com/DFE-Digital/publish-teacher-training)
154
+ * [Register trainee teachers](https://github.com/DFE-Digital/register-trainee-teachers)
155
+ * [Teaching Vacancies](https://github.com/DFE-Digital/teaching-vacancies)
156
+
157
+ ## Installation
158
+
159
+ Ajouter cette ligne à votre Gemfile:
160
+
161
+ ```ruby
162
+ gem 'dsfr-components'
163
+ ```
164
+
165
+ And then execute:
166
+
167
+ ```sh
168
+ bundle
169
+ ```
170
+
171
+ Or install it yourself as:
172
+
173
+ ```sh
174
+ gem install govuk-components
175
+ ```
176
+ -->
177
+
178
+ ## Contribuer
179
+
180
+ Nous conseillons d'utiliser [rbenv](https://github.com/rbenv/rbenv) pour gérer vos versions de ruby :
181
+
182
+ ```sh
183
+ rbenv local 3.1.2
184
+ rbenv install
185
+ ```
186
+
187
+ Lancer les tests :
188
+
189
+ ```sh
190
+ bundle install
191
+ bundle exec rspec spec
192
+ ```
193
+
194
+ Lancer le guide de documentation :
195
+
196
+ ```sh
197
+ make watch-guide
198
+ ```
199
+
200
+ Lancer la dummy app pour itérer sur les composants :
201
+
202
+ ```sh
203
+ cd spec/dummy
204
+ bundle install && npm install
205
+ bundle exec rails server
206
+ ```
207
+
208
+ Déployer une nouvelle version de la gem :
209
+
210
+ TODO
211
+
212
+ ## Licence
213
+
214
+ Le code source et la gem sont ouverts sous la licence [MIT](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Dsfr::Components'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
@@ -0,0 +1,11 @@
1
+ <%= tag.div(id: id(suffix: 'section'), **html_attributes) do %>
2
+ <div class="govuk-accordion__section-header">
3
+ <%= content_tag(heading_level, class: "govuk-accordion__section-heading") do %>
4
+ <%= tag.span(heading_content, id: id, class: "govuk-accordion__section-button", aria: { expanded: expanded?, controls: id(suffix: 'content') }) %>
5
+ <% end %>
6
+ <% if summary_content.present? %>
7
+ <%= tag.div(summary_content, id: id(suffix: 'summary'), class: %w(govuk-accordion__section-summary govuk-body)) %>
8
+ <% end %>
9
+ </div>
10
+ <%= tag.div(content, id: id(suffix: 'content'), class: %w(govuk-accordion__section-content), aria: { labelledby: id }) %>
11
+ <% end %>
@@ -0,0 +1,39 @@
1
+ class DsfrComponent::AccordionComponent::SectionComponent < DsfrComponent::Base
2
+ attr_reader :heading_text, :summary_text, :expanded, :heading_level
3
+
4
+ renders_one :heading_html
5
+ renders_one :summary_html
6
+
7
+ alias_method :expanded?, :expanded
8
+
9
+ def initialize(heading_text:, summary_text:, expanded:, heading_level:, classes: [], html_attributes: {})
10
+ @heading_text = heading_text
11
+ @summary_text = summary_text
12
+ @expanded = expanded
13
+ @heading_level = heading_level
14
+
15
+ super(classes: classes, html_attributes: html_attributes)
16
+ end
17
+
18
+ def id(suffix: nil)
19
+ # generate a random number if we don't have heading_text to avoid attempting
20
+ # to parameterize a potentially-huge chunk of HTML
21
+ @prefix ||= heading_text&.parameterize || SecureRandom.hex(4)
22
+
23
+ [@prefix, suffix].compact.join('-')
24
+ end
25
+
26
+ def heading_content
27
+ heading_html || heading_text || fail(ArgumentError, "no heading_text or heading_html")
28
+ end
29
+
30
+ def summary_content
31
+ summary_html || summary_text
32
+ end
33
+
34
+ private
35
+
36
+ def default_attributes
37
+ { class: class_names("govuk-accordion__section", "govuk-accordion__section--expanded" => expanded?).split }
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ <%= tag.div(**html_attributes) do %>
2
+ <% sections.each do |section| %>
3
+ <%= section %>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,33 @@
1
+ class DsfrComponent::AccordionComponent < DsfrComponent::Base
2
+ renders_many :sections, ->(heading_text: nil, summary_text: nil, expanded: false, classes: [], html_attributes: {}, &block) do
3
+ DsfrComponent::AccordionComponent::SectionComponent.new(
4
+ classes: classes,
5
+ expanded: expanded,
6
+ heading_level: heading_level, # set once at parent level, passed to all children
7
+ html_attributes: html_attributes,
8
+ summary_text: summary_text,
9
+ heading_text: heading_text,
10
+ &block
11
+ )
12
+ end
13
+
14
+ attr_reader :id, :heading_level
15
+
16
+ def initialize(heading_level: 2, classes: [], html_attributes: {})
17
+ @heading_level = heading_tag(heading_level)
18
+
19
+ super(classes: classes, html_attributes: html_attributes)
20
+ end
21
+
22
+ private
23
+
24
+ def default_attributes
25
+ { class: %w(govuk-accordion), data: { module: 'govuk-accordion' } }
26
+ end
27
+
28
+ def heading_tag(level)
29
+ fail(ArgumentError, "heading_level must be 1-6") unless level.in?(1..6)
30
+
31
+ %(h#{level})
32
+ end
33
+ end
@@ -0,0 +1,22 @@
1
+ class DsfrComponent::AlertComponent < DsfrComponent::Base
2
+ attr_reader :title
3
+
4
+ def initialize(title:, classes: [], html_attributes: {})
5
+ @title = title
6
+
7
+ super(classes: classes, html_attributes: html_attributes)
8
+ end
9
+
10
+ def call
11
+ tag.div(**html_attributes) do
12
+ tag.h3(class: "fr-alert__title") { title }
13
+ tag.p { content }
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def default_attributes
20
+ { class: %w(fr-alert) }
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ class DsfrComponent::BackLinkComponent < DsfrComponent::Base
2
+ attr_reader :text, :href
3
+
4
+ def initialize(href:, text: config.default_back_link_text, classes: [], html_attributes: {})
5
+ @text = text
6
+ @href = href
7
+
8
+ super(classes: classes, html_attributes: html_attributes)
9
+ end
10
+
11
+ def call
12
+ link_to(link_content, href, **html_attributes)
13
+ end
14
+
15
+ private
16
+
17
+ def link_content
18
+ content || text || fail(ArgumentError, "no text or content")
19
+ end
20
+
21
+ def default_attributes
22
+ { class: %w(govuk-back-link) }
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ class DsfrComponent::Base < ViewComponent::Base
2
+ using HTMLAttributesUtils
3
+
4
+ attr_reader :html_attributes
5
+
6
+ delegate :config, to: Dsfr::Components
7
+
8
+ def initialize(classes:, html_attributes:)
9
+ if classes.nil?
10
+ Rails.logger.warn("classes is nil, if no custom classes are needed omit the param")
11
+
12
+ classes = []
13
+ end
14
+ # FIXME: remove first merge when we deprecate classes
15
+ #
16
+ # This step only needs to be here while we still accept classes:, now
17
+ # we're using html_attributes_utils we can start to move towards
18
+ # supporting html_attributes: { class: 'xyz' } over taking them
19
+ # separately
20
+
21
+ @html_attributes = default_attributes
22
+ .deep_merge_html_attributes({ class: classes })
23
+ .deep_merge_html_attributes(html_attributes)
24
+ .deep_tidy_html_attributes
25
+
26
+ super
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ <%= tag.div(**html_attributes) do %>
2
+ <ol class="govuk-breadcrumbs__list">
3
+ <% @breadcrumbs.each do |link| %>
4
+ <%= link %>
5
+ <% end %>
6
+ </ol>
7
+ <% end %>
@@ -0,0 +1,51 @@
1
+ class DsfrComponent::BreadcrumbsComponent < DsfrComponent::Base
2
+ attr_reader :breadcrumbs, :hide_in_print, :collapse_on_mobile
3
+
4
+ def initialize(breadcrumbs:,
5
+ hide_in_print: config.default_breadcrumbs_hide_in_print,
6
+ collapse_on_mobile: config.default_breadcrumbs_collapse_on_mobile,
7
+ classes: [],
8
+ html_attributes: {})
9
+
10
+ @breadcrumbs = build_list(breadcrumbs)
11
+ @hide_in_print = hide_in_print
12
+ @collapse_on_mobile = collapse_on_mobile
13
+
14
+ super(classes: classes, html_attributes: html_attributes)
15
+ end
16
+
17
+ private
18
+
19
+ def default_attributes
20
+ {
21
+ class: class_names(
22
+ "govuk-breadcrumbs",
23
+ "govuk-!-display-none-print" => hide_in_print,
24
+ "govuk-breadcrumbs--collapse-on-mobile" => collapse_on_mobile
25
+ ).split
26
+ }
27
+ end
28
+
29
+ def build_list(breadcrumbs)
30
+ case breadcrumbs
31
+ when Array
32
+ breadcrumbs.map { |item| build_list_item(item) }
33
+ when Hash
34
+ breadcrumbs.map { |text, link| build_list_item(text, link) }
35
+ else
36
+ fail(ArgumentError, "breadcrumbs must be an array or hash")
37
+ end
38
+ end
39
+
40
+ def build_list_item(text, link = nil)
41
+ if link.present?
42
+ list_item { link_to(text, link, class: "govuk-breadcrumbs__link") }
43
+ else
44
+ list_item(aria: { current: "page" }) { text.to_s }
45
+ end
46
+ end
47
+
48
+ def list_item(html_attributes = {}, &block)
49
+ tag.li(class: "govuk-breadcrumbs__list-item", **html_attributes, &block)
50
+ end
51
+ end
@@ -0,0 +1,62 @@
1
+ class DsfrComponent::CookieBannerComponent::MessageComponent < DsfrComponent::Base
2
+ attr_reader :heading_text, :text, :hidden, :role
3
+
4
+ renders_many :actions
5
+ renders_one :heading_html
6
+
7
+ def initialize(heading_text: nil, text: nil, hidden: false, role: nil, classes: [], html_attributes: {})
8
+ @heading_text = heading_text
9
+ @text = text
10
+ @hidden = hidden
11
+ @role = role
12
+
13
+ super(classes: classes, html_attributes: html_attributes)
14
+ end
15
+
16
+ def call
17
+ tag.div(role: role, hidden: hidden, **html_attributes) do
18
+ safe_join([
19
+ tag.div(class: "govuk-grid-row") do
20
+ tag.div(class: "govuk-grid-column-two-thirds") { safe_join([heading_element, message_element]) }
21
+ end,
22
+ actions_element
23
+ ])
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def default_attributes
30
+ { class: %w(govuk-cookie-banner__message govuk-width-container) }
31
+ end
32
+
33
+ def heading_element
34
+ return if heading_content.blank?
35
+
36
+ tag.h2(heading_content, class: %w(govuk-cookie-banner__heading govuk-heading-m))
37
+ end
38
+
39
+ def heading_content
40
+ heading_html || heading_text
41
+ end
42
+
43
+ def message_element
44
+ tag.div(message_content, class: "govuk-cookie-banner__content")
45
+ end
46
+
47
+ def message_content
48
+ content || wrap_in_p(text) || fail(ArgumentError, "no text or content")
49
+ end
50
+
51
+ def wrap_in_p(message_text)
52
+ return if message_text.blank?
53
+
54
+ tag.p(message_text, class: "govuk-body")
55
+ end
56
+
57
+ def actions_element
58
+ return if actions.none?
59
+
60
+ tag.div(class: "fr-btn-group") { safe_join(actions) }
61
+ end
62
+ end
@@ -0,0 +1,35 @@
1
+ module DsfrComponent
2
+ class CookieBannerComponent < DsfrComponent::Base
3
+ renders_many :messages, "DsfrComponent::CookieBannerComponent::MessageComponent"
4
+
5
+ attr_accessor :aria_label, :hidden, :hide_in_print
6
+
7
+ def initialize(
8
+ aria_label: config.default_cookie_banner_aria_label,
9
+ hidden: false,
10
+ hide_in_print: config.default_cookie_banner_hide_in_print,
11
+ classes: [],
12
+ html_attributes: {}
13
+ )
14
+ @aria_label = aria_label
15
+ @hidden = hidden
16
+ @hide_in_print = hide_in_print
17
+
18
+ super(classes: classes, html_attributes: html_attributes)
19
+ end
20
+
21
+ def call
22
+ tag.div(role: "region", aria: { label: aria_label }, data: { nosnippet: true }, hidden: hidden, **html_attributes) do
23
+ safe_join(messages)
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def default_attributes
30
+ {
31
+ class: class_names("govuk-cookie-banner", "govuk-!-display-none-print" => hide_in_print).split
32
+ }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,42 @@
1
+ class DsfrComponent::DetailsComponent < DsfrComponent::Base
2
+ attr_reader :summary_text, :text, :id, :open
3
+
4
+ renders_one :summary_html
5
+
6
+ def initialize(summary_text: nil, text: nil, classes: [], id: nil, open: nil, html_attributes: {})
7
+ @summary_text = summary_text
8
+ @text = text
9
+ @id = id
10
+ @open = open
11
+
12
+ super(classes: classes, html_attributes: html_attributes)
13
+ end
14
+
15
+ def call
16
+ tag.details(data: { module: "govuk-details" }, id: id, open: open, **html_attributes) do
17
+ safe_join([summary, description])
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def summary
24
+ tag.summary(class: "govuk-details__summary") do
25
+ tag.span(summary_content, class: "govuk-details__summary-text")
26
+ end
27
+ end
28
+
29
+ def summary_content
30
+ summary_html || summary_text
31
+ end
32
+
33
+ def description
34
+ tag.div(class: "govuk-details__text") do
35
+ content.presence || text
36
+ end
37
+ end
38
+
39
+ def default_attributes
40
+ { class: %w(govuk-details) }
41
+ end
42
+ end
@@ -0,0 +1,49 @@
1
+ <%= tag.footer(role: 'contentinfo', **html_attributes) do %>
2
+ <%= tag.div(**container_html_attributes) do %>
3
+ <% if navigation.present? %>
4
+ <div class="govuk-footer__navigation">
5
+ <%= navigation %>
6
+ </div>
7
+
8
+ <hr class="govuk-footer__section-break">
9
+ <% end %>
10
+
11
+ <%= tag.div(class: meta_classes, **meta_html_attributes) do %>
12
+ <% if meta.present? %>
13
+ <%= meta %>
14
+ <% else %>
15
+ <div class="govuk-footer__meta-item govuk-footer__meta-item--grow">
16
+ <% if meta_items.any? %>
17
+ <h2 class="govuk-visually-hidden"><%= meta_items_title %></h2>
18
+
19
+ <ul class="govuk-footer__inline-list">
20
+ <% @meta_items.each do |hyperlink| %>
21
+ <li class="govuk-footer__inline-list-item">
22
+ <%= hyperlink %>
23
+ </li>
24
+ <% end %>
25
+ </ul>
26
+ <% end %>
27
+
28
+ <% if meta_licence.nil? %>
29
+ <svg aria-hidden="true" focusable="false" class="govuk-footer__licence-logo" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 483.2 195.7" height="17" width="41">
30
+ <path fill="currentColor" d="M421.5 142.8V.1l-50.7 32.3v161.1h112.4v-50.7zm-122.3-9.6A47.12 47.12 0 0 1 221 97.8c0-26 21.1-47.1 47.1-47.1 16.7 0 31.4 8.7 39.7 21.8l42.7-27.2A97.63 97.63 0 0 0 268.1 0c-36.5 0-68.3 20.1-85.1 49.7A98 98 0 0 0 97.8 0C43.9 0 0 43.9 0 97.8s43.9 97.8 97.8 97.8c36.5 0 68.3-20.1 85.1-49.7a97.76 97.76 0 0 0 149.6 25.4l19.4 22.2h3v-87.8h-80l24.3 27.5zM97.8 145c-26 0-47.1-21.1-47.1-47.1s21.1-47.1 47.1-47.1 47.2 21 47.2 47S123.8 145 97.8 145" />
31
+ </svg>
32
+
33
+ <%= tag.span(default_licence, class: "govuk-footer__licence-description") %>
34
+ <% elsif meta_licence.present? %>
35
+ <%= tag.span(meta_licence, class: "govuk-footer__licence-description") %>
36
+ <% end %>
37
+
38
+ <% if meta_content.present? %>
39
+ <div class="govuk-footer__meta-custom">
40
+ <%= meta_content %>
41
+ </div>
42
+ <% end %>
43
+ </div>
44
+
45
+ <%= tag.div(copyright, class: "govuk-footer__meta-item") %>
46
+ <% end %>
47
+ <% end %>
48
+ <% end %>
49
+ <% end %>