dsfr-view-components 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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 %>