Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat[#50499]: Add back button and breadcrumbs to page header #45

Merged
merged 28 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
fcb3934
feat[#50499]: Add back button and breadcrumbs to page header
dominic-braeunlein Oct 26, 2023
ee8a1dd
chore[#50499]: Set renders_one BackButton attributes size and icon de…
dominic-braeunlein Oct 31, 2023
648d4fc
fix[#50499]: Remove I18n from PageHeader
dominic-braeunlein Oct 31, 2023
3d70f16
fix[#50499]: Rename CSS class PageHeader-back_button to PageHeader-ba…
dominic-braeunlein Oct 31, 2023
017bbda
fix[#50499]: Fix RuboCop errors and warnings
dominic-braeunlein Oct 31, 2023
5bf4dae
fix[#50499]: Vertically center back button
dominic-braeunlein Nov 1, 2023
fee9a1a
fix[#50499]: Add aria-label in preview for with_back_button
dominic-braeunlein Nov 1, 2023
4a96f5f
test[#50499]: Add renders_back_button test
dominic-braeunlein Nov 1, 2023
e3da4f1
test[#50499]: Add renders_breadcrumbs test
dominic-braeunlein Nov 1, 2023
59e5324
fix[#50499]: Fix class names in PageHeader
dominic-braeunlein Nov 1, 2023
3f91140
chore[#50499]: Remove show_breadcrumb option in PageHeader.with_bread…
dominic-braeunlein Nov 1, 2023
67b763f
chore[#50499]: Remove manually added static classes
dominic-braeunlein Nov 1, 2023
83513c4
feat[#50499]: Support **system_arguments in PageHeader breadcrumbs slot
dominic-braeunlein Nov 1, 2023
68f12e0
fix[#50499]: Readd @label With actions in PageHeaderPreview
dominic-braeunlein Nov 1, 2023
33a363d
fix[#50499]: Fix spaces
dominic-braeunlein Nov 1, 2023
b5069e0
fix[#50499]: Change PageHeader align-items to baseline
dominic-braeunlein Nov 7, 2023
76f469d
fix[#50499]: Add size and icon options and use fetch_or_fallback
dominic-braeunlein Nov 7, 2023
4f57dc1
chore[#50499]: Add params options in preview for PageHeader with back…
dominic-braeunlein Nov 7, 2023
18e5c94
chore[#50499]: Add params information in back_button slot
dominic-braeunlein Nov 7, 2023
2f4ad11
chore[#50499]: Add params options in preview for PageHeader with brea…
dominic-braeunlein Nov 7, 2023
6db5989
chore[#50499]: Add anchor_tag_string helper function
dominic-braeunlein Nov 7, 2023
cdc8973
fix[#50499]: Fix back button and title wrapping on small screen
dominic-braeunlein Nov 7, 2023
4f0227e
chore[#50499]: Remove long testing title from preview
dominic-braeunlein Nov 8, 2023
5f79542
chore[#50499]: Remove back button in breadcrumb preview
dominic-braeunlein Nov 8, 2023
a0afd49
chore[#50499]: Sort PageHeader with-alternatives alphabetically
dominic-braeunlein Nov 8, 2023
7ee873c
chore[#50499]: Add toggles for back button and breadcrumbs in playground
dominic-braeunlein Nov 8, 2023
dbfdaf9
chore[#50499]: Add back button size parameter to playground
dominic-braeunlein Nov 8, 2023
6ce609d
Center back button in any cases. Unfortunately, there is a two pixel …
HDinger Nov 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/green-bananas-kneel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@openproject/primer-view-components': minor
---

Add back button and breadcrumbs support to PageHeader
8 changes: 6 additions & 2 deletions app/components/primer/open_project/page_header.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
<%= title %>
<%= breadcrumbs %>
<div class="PageHeader-titleBar">
<%= back_button %>
<%= title %>
<%= actions %>
</div>
<%= description %>
<%= actions %>
<% end %>
25 changes: 19 additions & 6 deletions app/components/primer/open_project/page_header.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,24 @@
padding-bottom: var(--stack-padding-condensed);
margin-bottom: var(--stack-gap-normal);
border-bottom: var(--borderWidth-thin) solid var(--borderColor-muted);
flex-flow: row wrap;
justify-content: flex-end; /* Keep actions right aligned. */
flex-flow: column;

@media (max-width: 767.98px) {
border-bottom: 0;
}
}

.PageHeader-titleBar {
display: flex;
flex-flow: row;
justify-content: flex-end;
align-items: center; /* Keep back button vertically aligned. */
}

.PageHeader-title {
font-size: 24px;
font-weight: var(--base-text-weight-normal);
flex: 1 1 auto;
order: 0;
}

.PageHeader-title--large {
Expand All @@ -29,17 +34,25 @@
font-size: var(--text-body-size-medium);
color: var(--fgColor-muted);
flex: 1 100%;
order: 2;
}

/* Add 1 or 2 buttons to the right of the heading */
.PageHeader-actions {
margin: var(--base-size-4) 0 var(--base-size-4) var(--base-size-4);
align-self: center;
justify-content: flex-end;
order: 1;

& + .PageHeader-description {
margin-top: var(--base-size-4);
}
}

.PageHeader-breadcrumbs {
display: block;
width: 100%;
margin-bottom: var(--base-size-8);
}

.PageHeader-backButton {
margin-top: 2px; /* to center align with label */
margin-right: var(--base-size-4);
}
70 changes: 70 additions & 0 deletions app/components/primer/open_project/page_header.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ class PageHeader < Primer::Component
DEFAULT_HEADER_VARIANT
].freeze

DEFAULT_BACK_BUTTON_SIZE = :medium
BACK_BUTTON_SIZE_OPTIONS = [
:small,
DEFAULT_HEADER_VARIANT,
:large
].freeze

DEFAULT_BACK_BUTTON_ICON = "arrow-left"
BACK_BUTTON_ICON_OPTIONS = [
DEFAULT_BACK_BUTTON_ICON,
"chevron-left",
"triangle-left"
].freeze

status :open_project

# The title of the page header
Expand Down Expand Up @@ -50,6 +64,45 @@ class PageHeader < Primer::Component
Primer::BaseComponent.new(**system_arguments)
}

# Optional back button prepend the title
#
# @param size [Symbol] <%= one_of(Primer::OpenProject::PageHeader::BACK_BUTTON_SIZE_OPTIONS) %>
# @param icon [String] <%= one_of(Primer::OpenProject::PageHeader::BACK_BUTTON_ICON_OPTIONS) %>
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
renders_one :back_button, lambda { |
dominic-braeunlein marked this conversation as resolved.
Show resolved Hide resolved
size: DEFAULT_BACK_BUTTON_SIZE,
icon: DEFAULT_BACK_BUTTON_ICON,
dominic-braeunlein marked this conversation as resolved.
Show resolved Hide resolved
**system_arguments
|
deny_tag_argument(**system_arguments)
system_arguments[:tag] = :a
system_arguments[:scheme] = :invisible
system_arguments[:size] = fetch_or_fallback(BACK_BUTTON_SIZE_OPTIONS, size, DEFAULT_BACK_BUTTON_SIZE)
system_arguments[:icon] = fetch_or_fallback(BACK_BUTTON_ICON_OPTIONS, icon, DEFAULT_BACK_BUTTON_ICON)
system_arguments[:classes] = class_names(system_arguments[:classes], "PageHeader-backButton")

Primer::Beta::IconButton.new(**system_arguments)
}

# Optional breadcrumbs above the title row
#
# @param items [Array<String, Hash>] Items is an array of strings, hash {href, text} or an anchor tag string
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
renders_one :breadcrumbs, lambda { |items, **system_arguments|
system_arguments[:classes] = class_names(system_arguments[:classes], "PageHeader-breadcrumbs")
render(Primer::Beta::Breadcrumbs.new(**system_arguments)) do |breadcrumbs|
items.each do |item|
item = anchor_string_to_object(item) if anchor_tag_string?(item)

if item.is_a?(String)
breadcrumbs.with_item(href: "#") { item }
else
breadcrumbs.with_item(href: item[:href]) { item[:text] }
end
end
end
}

def initialize(**system_arguments)
@system_arguments = deny_tag_argument(**system_arguments)

Expand All @@ -64,6 +117,23 @@ def initialize(**system_arguments)
def render?
title?
end

private

# transform anchor tag strings to {href, text} objects
# e.g "\u003ca href=\"/admin\"\u003eAdministration\u003c/a\u003e"
def anchor_string_to_object(html_string)
# Parse the HTML
doc = Nokogiri::HTML.fragment(html_string)
# Extract href and text
anchor = doc.at("a")
{ href: anchor["href"], text: anchor.text }
end

# Check if the item is an anchor tag string e.g "\u003ca href=\"/admin\"\u003eAdministration\u003c/a\u003e"
def anchor_tag_string?(item)
item.is_a?(String) && item.start_with?("\u003c")
end
dominic-braeunlein marked this conversation as resolved.
Show resolved Hide resolved
end
end
end
40 changes: 39 additions & 1 deletion previews/primer/open_project/page_header_preview.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,24 @@ def default
# @param variant [Symbol] select [medium, large]
# @param title [String] text
# @param description [String] text
def playground(variant: :medium, title: "Hello", description: "Last updated 5 minutes ago by XYZ.")
# @param with_back_button [Boolean]
# @param back_button_size [Symbol] select [small, medium, large]
# @param with_breadcrumbs [Boolean]
def playground(
variant: :medium,
title: "Hello",
description: "Last updated 5 minutes ago by XYZ.",
with_back_button: false,
back_button_size: :medium,
with_breadcrumbs: false
)
breadcrumb_items = [{ href: "/foo", text: "Foo" }, { href: "/bar", text: "Bar" }, "Baz"]

render(Primer::OpenProject::PageHeader.new) do |header|
header.with_title(variant: variant) { title }
header.with_description { description }
header.with_back_button(href: "#", size: back_button_size, 'aria-label': "Back") if with_back_button
header.with_breadcrumbs(breadcrumb_items) if with_breadcrumbs
end
end

Expand All @@ -37,6 +51,30 @@ def large_title
def actions
render_with_template(locals: {})
end

# @label With back button
# @param href [String] text
# @param size [Symbol] select [small, medium, large]
# @param icon [String] select ["arrow-left", "chevron-left", "triangle-left"]
def back_button(href: "#", size: :medium, icon: "arrow-left")
render(Primer::OpenProject::PageHeader.new) do |header|
header.with_title { "Hello" }
header.with_back_button(href: href, size: size, icon: icon, 'aria-label': "Back")
end
end

# @label With breadcrumbs
def breadcrumbs
breadcrumb_items = [
{ href: "/foo", text: "Foo" },
"\u003ca href=\"/foo/bar\"\u003eBar\u003c/a\u003e",
"Baz"
]
render(Primer::OpenProject::PageHeader.new) do |header|
header.with_title { "A title" }
header.with_breadcrumbs(breadcrumb_items)
end
end
end
end
end
33 changes: 33 additions & 0 deletions test/components/primer/open_project/page_header_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,37 @@ def test_renders_actions
assert_text("An action")
assert_selector(".PageHeader-actions")
end

def test_renders_back_button
render_inline(Primer::OpenProject::PageHeader.new) do |header|
header.with_title { "Hello" }
header.with_back_button(href: "/link", 'aria-label': "Back")
end

assert_text("Hello")
assert_selector(".PageHeader-title")
assert_selector(".PageHeader-backButton")
assert_selector(".Button-withTooltip a[href='/link']")
end

def test_renders_breadcrumbs
breadcrumb_items = [
{ href: "/foo", text: "Foo" },
"\u003ca href=\"/foo/bar\"\u003eBar\u003c/a\u003e",
"test"
]

render_inline(Primer::OpenProject::PageHeader.new) do |header|
header.with_title { "Hello" }
header.with_breadcrumbs(breadcrumb_items)
end

assert_text("Hello")
assert_selector(".PageHeader-title")
assert_selector(".PageHeader-breadcrumbs")

assert_selector("nav[aria-label='Breadcrumb'].PageHeader-breadcrumbs .breadcrumb-item a[href='/foo']")
assert_selector("nav[aria-label='Breadcrumb'].PageHeader-breadcrumbs .breadcrumb-item a[href='/foo/bar']")
assert_selector("nav[aria-label='Breadcrumb'].PageHeader-breadcrumbs .breadcrumb-item a[href='#']")
end
end
Loading