Skip to content

Commit

Permalink
Add task list component (#445)
Browse files Browse the repository at this point in the history
This PR adds the upcoming [Task list
component](/alphagov/govuk-design-system/pull/1994). It's built in a
similar fashion to the summary list.

Tags can be added within statuses by calling `govuk_tag` within the
status, or plain text can be used.
  • Loading branch information
peteryates authored Nov 3, 2023
2 parents b95a714 + 342eb42 commit 40b2745
Show file tree
Hide file tree
Showing 12 changed files with 625 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ The provided components are:
* [Tabs](https://govuk-components.netlify.app/components/tabs)
* [Tables](https://govuk-components.netlify.app/components/table)
* [Tags](https://govuk-components.netlify.app/components/tag)
* [Task list](https://govuk-components.netlify.app/components/task-list)
* [Warning text](https://govuk-components.netlify.app/components/warning-text)

This library also provides helpers for creating [links](https://govuk-components.netlify.app/helpers/link),
Expand Down
37 changes: 37 additions & 0 deletions app/components/govuk_component/task_list_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module GovukComponent
class TaskListComponent < GovukComponent::Base
renders_many :items, ->(title: nil, href: nil, hint: nil, status: {}, classes: [], html_attributes: {}) do
GovukComponent::TaskListComponent::ItemComponent.new(
title: title,
href: href,
hint: hint,
id_prefix: @id_prefix,
count: @count,
status: status,
classes: classes,
html_attributes: html_attributes
)
end

def initialize(id_prefix: "task-list", classes: [], html_attributes: {})
@id_prefix = id_prefix
@count = 0

super(classes: classes, html_attributes: html_attributes)
end

def call
numbered_items = items.each.with_index(1) { |item, count| item.count = count }

tag.ul(**html_attributes) do
safe_join(numbered_items)
end
end

private

def default_attributes
{ class: 'govuk-task-list' }
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
module GovukComponent
class TaskListComponent::ItemComponent < GovukComponent::Base
renders_one :status, ->(text: nil, classes: [], html_attributes: {}, &block) do
GovukComponent::TaskListComponent::StatusComponent.new(
id_prefix: @id_prefix,
count: @count,
text: text,
classes: classes,
html_attributes: html_attributes,
&block
)
end

renders_one :title, ->(text: nil, href: nil, hint: nil, classes: [], html_attributes: {}, &block) do
GovukComponent::TaskListComponent::TitleComponent.new(
id_prefix: @id_prefix,
count: @count,
text: text,
href: href,
hint: hint,
classes: classes,
html_attributes: html_attributes,
&block
)
end

attr_reader :raw_title, :hint, :href, :raw_status
attr_writer :count

def initialize(title: nil, href: nil, hint: nil, count: nil, id_prefix: nil, status: {}, classes: [], html_attributes: {})
@raw_title = title
@href = href
@hint = hint
@raw_status = status
@id_prefix = id_prefix
@count = count

super(classes: classes, html_attributes: html_attributes)
end

def call
adjusted_html_attributes = if href.present? || title&.href.present?
html_attributes_with_link_class
else
html_attributes
end

tag.li(safe_join([title_content, status_content].compact), **adjusted_html_attributes)
end

private

def title_content
title || with_title(**title_attributes)
end

def status_content
status || with_status(**status_attributes)
end

def default_attributes
{ class: 'govuk-task-list__item' }
end

def title_attributes
{ text: raw_title, href: href, hint: hint }
end

def html_attributes_with_link_class
html_attributes.tap { |h| h[:class].append("govuk-task-list__item--with-link") }
end

def status_attributes
raw_status.is_a?(String) ? { text: raw_status } : raw_status
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module GovukComponent
class TaskListComponent::StatusComponent < GovukComponent::Base
attr_reader :id_prefix, :text, :count

def initialize(text: nil, id_prefix: nil, count: nil, classes: [], html_attributes: {})
@text = text
@count = count
@id_prefix = id_prefix

super(classes: classes, html_attributes: html_attributes)
end

def call
tag.div(status_text, **html_attributes)
end

def render?
status_text.present?
end

private

def default_attributes
{ class: %w(govuk-task-list__status), id: [id_prefix, count, "status"].compact.join("-") }
end

def status_text
text || content
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
module GovukComponent
class TaskListComponent::TitleComponent < GovukComponent::Base
using HTMLAttributesUtils

attr_reader :id_prefix, :text, :href, :hint, :count

def initialize(text: nil, href: nil, hint: nil, id_prefix: nil, count: nil, classes: [], html_attributes: {})
@text = text
@href = href
@hint = hint
@id_prefix = id_prefix
@count = count

super(classes: classes, html_attributes: html_attributes)
end

def call
tag.div(**html_attributes) { safe_join([title_content, hint_content]) }
end

private

def title_content
(href.present?) ? govuk_link_to(text, href, **link_attributes) : text
end

def hint_content
return if hint.blank?

tag.div(hint, class: "govuk-task-list__hint", id: hint_id)
end

def default_attributes
{ class: "govuk-task-list__name-and-hint" }
end

def link_attributes
{ class: "govuk-task-list__link", **aria_described_by_attributes }
end

def aria_described_by_attributes
{ aria: { describedby: [*status_id, *hint_id] } }
end

def hint_id
[id_prefix, count, "hint"].compact.join("-") if hint.present?
end

def status_id
[id_prefix, count, "status"].compact.join("-")
end
end
end
1 change: 1 addition & 0 deletions app/helpers/govuk_components_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module GovukComponentsHelper
govuk_table: 'GovukComponent::TableComponent',
govuk_tabs: 'GovukComponent::TabComponent',
govuk_tag: 'GovukComponent::TagComponent',
govuk_task_list: 'GovukComponent::TaskListComponent',
govuk_warning_text: 'GovukComponent::WarningTextComponent',
}.each do |name, klass|
define_method(name) do |*args, **kwargs, &block|
Expand Down
47 changes: 47 additions & 0 deletions guide/content/components/task-list.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
title: Task list
---

markdown:
The task list component displays a list of related tasks that user needs to do, and allows
them to easily identify which ones are done and which they still need to do.

You can have multiple tasks lists on a page. Where you have multiple tasks lists, you must add a unique `id_prefix` to each one.

== render('/partials/example.*',
caption: "Default task list",
code: default_task_list)

markdown:
Task statuses can either contain plain text, or can contain a [`govuk_tag`](/components/tag).

== render('/partials/example.*',
caption: "Task list with coloured tags",
code: task_list_with_coloured_tags) do

markdown:
The tags can be given different colours by passing a `colour` keyword.

== render('/partials/example.*',
caption: "Task list with hints",
code: task_list_with_hints) do

markdown:
When an explanation is needed to better describe a task, hints can be added
with the `hint` keyword on either `with_item` or `with_title`.

== render('/partials/example.*',
caption: "Task list with cannot start yet items",
code: task_list_with_cannot_start_yet) do

markdown:
Tasks can omit the `href` keyword if they cannot be started yet. When doing this you should add the `govuk-task-list__status--cannot-start-yet` to the status, and a hint to explain why the task cannot be started yet.

== render('/partials/example.*',
caption: "Task list with custom classes",
code: task_list_with_custom_classes) do

markdown:
If you need to customise the task list, you can add custom modifier classes to the task list, items, titles or statuses.

You can also add additional html attributes using the `html_attributes` keyword.
73 changes: 73 additions & 0 deletions guide/lib/examples/task_list_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
module Examples
module TaskListHelpers
def default_task_list
<<~SNIPPET
h2.govuk-heading-m About you
= govuk_task_list(id_prefix: "about-you") do |task_list|
- task_list.with_item(title: "Personal details", href: '#', status: "Completed")
- task_list.with_item(title: "Contact details", href: '#', status: govuk_tag(text: "Incomplete", colour: "blue"))
h2.govuk-heading-m Your project
= govuk_task_list(id_prefix: "your-project") do |task_list|
- task_list.with_item(title: "Project description", href: '#', status: "Completed")
- task_list.with_item(title: "Funding", href: '#', status: govuk_tag(text: "Incomplete", colour: "blue"))
SNIPPET
end

def task_list_with_cannot_start_yet
<<~SNIPPET
= govuk_task_list(id_prefix: "project-tasks") do |task_list|
- task_list.with_item(title: "Contact details", href: '#', status: "Completed")
- task_list.with_item(title: "Project details", href: '#', status: "Completed")
- task_list.with_item(title: "Funding", hint: "The funds will be announced on 1 April 2022") do |item|
- item.with_status(text: "Cannot start yet", classes: "govuk-task-list__status--cannot-start-yet")
SNIPPET
end

def task_list_with_coloured_tags
<<~SNIPPET
= govuk_task_list(id_prefix: "coloured-tags-example") do |task_list|
- task_list.with_item(title: "Design", href: "#", status: govuk_tag(text: "Green", colour: "green"))
- task_list.with_item(title: "Prototype", href: "#", status: govuk_tag(text: "Blue", colour: "blue"))
- task_list.with_item(title: "Implementation", href: "#", status: govuk_tag(text: "Light blue", colour: "light-blue"))
- task_list.with_item(title: "User acceptance testing", href: "#", status: govuk_tag(text: "Red", colour: "red"))
- task_list.with_item(title: "Handover", href: "#") do |item|
- item.with_status do
= govuk_tag(text: "Turquoise", colour: "turquoise")
SNIPPET
end

def task_list_with_hints
<<~SNIPPET
= govuk_task_list(id_prefix: "task-list-with-hints") do |task_list|
- task_list.with_item(title: "Check your qualifications", hint: "You need GCSEs in English and maths", href: "#", status: govuk_tag(text: "Done", colour: "green"))
- task_list.with_item do |item|
- item.with_title(text: "Understand funding", hint: "Teacher training course fees are around £9,250 per year", href: "#")
- item.with_status(text: govuk_tag(text: "Done", colour: "green"))
- task_list.with_item do |item|
- item.with_title(text: "Consider getting experience", hint: "Experiencing life in a school can help you decide if teaching is right for you", href: "#")
- item.with_status(text: govuk_tag(text: "Arranged", colour: "yellow"))
- task_list.with_item do |item|
- item.with_title(text: "Find a teacher training course", hint: "Through teacher training you can get QTS, a PGCE, or both", href: "#")
- item.with_status(text: govuk_tag(text: "To do", colour: "red"))
SNIPPET
end

def task_list_with_custom_classes
<<~SNIPPET
= govuk_task_list(id_prefix: "task-list-with-custom-classes", classes: "app-task-list--my-modifier", html_attributes: {"data-my-key" => "my-value"}) do |task_list|
- task_list.with_item(classes: "app-task-list__item--my-modifier") do |item|
- item.with_title(text: "Personal details", href: "#", classes: "app-task-list__name-and-hint--my-modifier")
- item.with_status(text: "Completed", classes: "app-task-list__status--my-modifier")
- task_list.with_item(classes: "app-task-list__item--my-modifier") do |item|
- item.with_title(text: "Contact information", href: "#", classes: "app-task-list__name-and-hint--my-modifier")
- item.with_status(text: "Completed", classes: "app-task-list__status--my-modifier")
SNIPPET
end
end
end
5 changes: 5 additions & 0 deletions guide/lib/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ class Application < Rails::Application; end
require 'components/govuk_component/table_component/foot_component'
require 'components/govuk_component/tab_component'
require 'components/govuk_component/tag_component'
require 'components/govuk_component/task_list_component'
require 'components/govuk_component/task_list_component/item_component'
require 'components/govuk_component/task_list_component/status_component'
require 'components/govuk_component/task_list_component/title_component'
require 'components/govuk_component/warning_text_component'

require 'helpers/govuk_link_helper'
Expand All @@ -106,6 +110,7 @@ class Application < Rails::Application; end
use_helper Examples::TableHelpers
use_helper Examples::TabsHelpers
use_helper Examples::TagHelpers
use_helper Examples::TaskListHelpers
use_helper Examples::WarningTextHelpers
use_helper Examples::CommonOptionsHelpers
use_helper Examples::BackToTopLinkHelpers
Expand Down
1 change: 1 addition & 0 deletions guide/lib/helpers/link_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def component_links
"Table" => "/components/table",
"Tabs" => "/components/tabs",
"Tag" => "/components/tag",
"Task list" => "/components/task-list",
"Warning text" => "/components/warning-text",
}
end
Expand Down
Loading

0 comments on commit 40b2745

Please sign in to comment.