-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: create sub navigation view component
- Loading branch information
Showing
7 changed files
with
291 additions
and
0 deletions.
There are no files selected for viewing
51 changes: 51 additions & 0 deletions
51
app/components/navigation/structures/admin_sub_navigation.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
module Navigation | ||
module Structures | ||
class AdminSubNavigation < Navigation::Structures::BaseSubNavigation | ||
def get | ||
[ | ||
Node.new( | ||
name: "Admin", | ||
href: "#", | ||
prefix: "/admin", | ||
nodes: [ | ||
Node.new( | ||
name: "Admin 1.1", | ||
href: '#', | ||
prefix: "/admin/1.1" | ||
), | ||
Node.new( | ||
name: "Admin 1.2", | ||
href: '#', | ||
prefix: "/admin/1.2" | ||
) | ||
] | ||
), | ||
Node.new( | ||
name: "Sub Nav 2", | ||
href: '#', | ||
prefix: "/sub-nav-2", | ||
nodes: [ | ||
Node.new( | ||
name: "Sub Nav 2.1", | ||
href: '#', | ||
prefix: "/sub-nav-2.1" | ||
), | ||
] | ||
), | ||
Node.new( | ||
name: "Sub Nav 3", | ||
href: '#', | ||
prefix: "/sub-nav-3", | ||
nodes: [ | ||
Node.new( | ||
name: "Sub Nav 3.1", | ||
href: '#', | ||
prefix: "/sub-nav-3.1" | ||
), | ||
] | ||
), | ||
] | ||
end | ||
end | ||
end | ||
end |
19 changes: 19 additions & 0 deletions
19
app/components/navigation/structures/base_sub_navigation.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
module Navigation | ||
module Structures | ||
class BaseSubNavigation | ||
include Rails.application.routes.url_helpers | ||
|
||
# A Node is an entry in a navigation list, it contains: | ||
# | ||
# * name - the hyperlink text which appears in the list | ||
# * href - the hyperlink href | ||
# * prefix - the beginning of a path which will trigger the node to be marked | ||
# 'current' and highlighted in the nav | ||
# * current - a boolean value where the result of the prefix match is stored, | ||
# this isn't done on the fly so we can pass the value along from | ||
# the primary nav to the sub nav | ||
# * nodes - a list of nodes that sit under this one in the structure | ||
Node = Struct.new(:name, :href, :prefix, :nodes) | ||
end | ||
end | ||
end |
20 changes: 20 additions & 0 deletions
20
app/components/navigation/sub_navigation_component.html.erb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<nav class="x-govuk-sub-navigation" aria-labelledby="sub-navigation-heading"> | ||
<h2 class="govuk-visually-hidden" id="sub-navigation-heading">Navigation</h2> | ||
<ul class="x-govuk-sub-navigation__section"> | ||
<% structure.each do |section| %> | ||
<%= tag.li(class: navigation_item_classes(section)) do %> | ||
<%= navigation_link(section) %> | ||
<% if section.nodes.present? %> | ||
<ul class="x-govuk-sub-navigation__section x-govuk-sub-navigation__section--nested"> | ||
<% section.nodes.each do |node| %> | ||
<li class="x-govuk-sub-navigation__section-item"> | ||
<%= navigation_link(node) %> | ||
</li> | ||
<% end %> | ||
</ul> | ||
<% end %> | ||
<% end %> | ||
<% end %> | ||
</ul> | ||
</nav> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
require 'debug' | ||
|
||
module Navigation | ||
class SubNavigationComponent < ViewComponent::Base | ||
attr_accessor :current_path, :current_section, :structure | ||
|
||
def initialize(current_path, structure:) | ||
@current_path = current_path | ||
@structure = structure | ||
end | ||
|
||
def render? | ||
structure.present? | ||
end | ||
|
||
def navigation_link(section) | ||
link_to( | ||
section.name, | ||
section.href, | ||
class: "x-govuk-sub-navigation__link", | ||
aria: { current: current?(section.prefix) }, | ||
) | ||
end | ||
|
||
def navigation_item_classes(section) | ||
class_names( | ||
"x-govuk-sub-navigation__section-item", | ||
"x-govuk-sub-navigation__section-item--current" => current?(section.prefix), | ||
) | ||
end | ||
|
||
private | ||
|
||
def current?(prefix) | ||
# return nil instead of false so Rails' link helper drops the | ||
# attribute rather than setting "current='false'" | ||
current_path.start_with?(prefix) || nil | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module AdminHelper | ||
def admin_sub_navigation_structure | ||
@admin_navigation_structure ||= Navigation::Structures::AdminSubNavigation.new.get | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
spec/components/navigation/sub_navigation_component_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
require "rails_helper" | ||
|
||
class TestSubNavigationStructureTwoLevels < Navigation::Structures::BaseSubNavigation | ||
def get | ||
[ | ||
Node.new( | ||
name: "This is the Sub Nav 1 page", | ||
href: "/sub-nav-1", | ||
prefix: "/sub-nav-1", | ||
nodes: [ | ||
Node.new( | ||
name: "This is the Sub Nav 1.1 page", | ||
href: "/sub-nav-1.1", | ||
prefix: "/sub-nav-1.1" | ||
), | ||
] | ||
), | ||
Node.new( | ||
name: "This is the Sub Nav 2 page", | ||
href: "/sub-nav-2", | ||
prefix: "/sub-nav-2", | ||
nodes: [ | ||
Node.new( | ||
name: "This is the Sub Nav 2.1 page", | ||
href: '/sub-nav-2.1', | ||
prefix: "/sub-nav-2.1" | ||
), | ||
] | ||
), | ||
] | ||
end | ||
end | ||
|
||
class TestSubNavigationStructureOneLevel < Navigation::Structures::BaseSubNavigation | ||
def get | ||
[ | ||
Node.new( | ||
name: "This is the Sub Nav 1 page", | ||
href: '/sub-nav-1', | ||
prefix: "/sub-nav-1", | ||
) | ||
] | ||
end | ||
end | ||
|
||
RSpec.describe Navigation::SubNavigationComponent, type: :component do | ||
describe "a nested navigation structure with two levels" do | ||
let(:current_path) { "/some-path" } | ||
let(:structure) { TestSubNavigationStructureTwoLevels.new } | ||
|
||
subject do | ||
Navigation::SubNavigationComponent.new(current_path, structure: structure.get) | ||
end | ||
|
||
it "renders a visually hidden h2 heading" do | ||
render_inline(subject) | ||
|
||
expect(rendered_content).to have_css("h2.govuk-visually-hidden", text: "Navigation") | ||
end | ||
|
||
it "renders top level navigation items" do | ||
render_inline(subject) | ||
|
||
selector = "li.x-govuk-sub-navigation__section-item > a.x-govuk-sub-navigation__link" | ||
|
||
expect(rendered_content).to have_css(selector, text: "This is the Sub Nav 1 page") | ||
expect(rendered_content).to have_css(selector, text: "This is the Sub Nav 2 page") | ||
end | ||
|
||
it "renders second level navigation items" do | ||
render_inline(subject) | ||
|
||
selector = %w[ | ||
li.x-govuk-sub-navigation__section-item | ||
ul.x-govuk-sub-navigation__section--nested | ||
li.x-govuk-sub-navigation__section-item | ||
a.x-govuk-sub-navigation__link | ||
].join(" > ") | ||
|
||
expect(rendered_content).to have_css(selector, text: "This is the Sub Nav 1.1 page") | ||
expect(rendered_content).to have_css(selector, text: "This is the Sub Nav 2.1 page") | ||
end | ||
end | ||
|
||
describe "a navigation structure with only one level" do | ||
let(:structure) { TestSubNavigationStructureOneLevel.new } | ||
let(:current_path) { "/some-path" } | ||
|
||
subject do | ||
Navigation::SubNavigationComponent.new(current_path, structure: structure.get) | ||
end | ||
|
||
it "renders top level navigation items" do | ||
render_inline(subject) | ||
|
||
selector = "li.x-govuk-sub-navigation__section-item > a.x-govuk-sub-navigation__link" | ||
|
||
expect(rendered_content).to have_css(selector, text: "This is the Sub Nav 1 page") | ||
end | ||
end | ||
|
||
describe "highlighting the current top level nav item" do | ||
context "when the prefix matches the start of the current path" do | ||
let(:current_path) { "/sub-nav-1" } | ||
let(:structure) { TestSubNavigationStructureTwoLevels.new } | ||
|
||
subject do | ||
Navigation::SubNavigationComponent.new(current_path, structure: structure.get) | ||
end | ||
|
||
it "marks only the nav item with the matching prefix as 'current'" do | ||
render_inline(subject) | ||
|
||
selector = "li.x-govuk-sub-navigation__section-item--current" | ||
|
||
expect(rendered_content).to have_css(selector, text: "This is the Sub Nav 1 page") | ||
expect(rendered_content).to have_css(selector, count: 1) | ||
end | ||
end | ||
end | ||
|
||
describe "highlighting the current second level nav item" do | ||
context "when the prefix matches the start of the current path" do | ||
let(:current_path) { "/sub-nav-1.1" } | ||
let(:structure) { TestSubNavigationStructureTwoLevels.new } | ||
|
||
subject do | ||
Navigation::SubNavigationComponent.new(current_path, structure: structure.get) | ||
end | ||
|
||
it "marks only the section as current" do | ||
render_inline(subject) | ||
|
||
selector = %w[ | ||
li.x-govuk-sub-navigation__section-item | ||
ul.x-govuk-sub-navigation__section--nested | ||
li.x-govuk-sub-navigation__section-item | ||
a.x-govuk-sub-navigation__link[aria-current="true"] | ||
].join(" > ") | ||
|
||
expect(rendered_content).to have_css(selector, text: "This is the Sub Nav 1.1 page") | ||
expect(rendered_content).to have_css(selector, count: 1) | ||
end | ||
end | ||
end | ||
end |