openproject-primer_view_components 0.31.0 → 0.32.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/app/assets/javascripts/app/components/primer/open_project/sub_header_element.d.ts +13 -0
- data/app/assets/javascripts/app/components/primer/primer.d.ts +1 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/assets/styles/primer_view_components.css +1 -1
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/open_project/page_header.rb +1 -1
- data/app/components/primer/open_project/sub_header.css +1 -0
- data/app/components/primer/open_project/sub_header.css.json +11 -0
- data/app/components/primer/open_project/sub_header.css.map +1 -0
- data/app/components/primer/open_project/sub_header.html.erb +25 -0
- data/app/components/primer/open_project/sub_header.pcss +42 -0
- data/app/components/primer/open_project/sub_header.rb +140 -0
- data/app/components/primer/open_project/sub_header_element.d.ts +13 -0
- data/app/components/primer/open_project/sub_header_element.js +44 -0
- data/app/components/primer/open_project/sub_header_element.ts +45 -0
- data/app/components/primer/primer.d.ts +1 -0
- data/app/components/primer/primer.js +1 -0
- data/app/components/primer/primer.pcss +1 -0
- data/app/components/primer/primer.ts +1 -0
- data/lib/primer/view_components/version.rb +2 -2
- data/previews/primer/open_project/sub_header_preview/action_menu_buttons.html.erb +15 -0
- data/previews/primer/open_project/sub_header_preview/bottom_pane.html.erb +12 -0
- data/previews/primer/open_project/sub_header_preview/button_group.html.erb +11 -0
- data/previews/primer/open_project/sub_header_preview/custom_filter_button.html.erb +8 -0
- data/previews/primer/open_project/sub_header_preview/dialog_buttons.html.erb +12 -0
- data/previews/primer/open_project/sub_header_preview.rb +88 -0
- data/static/arguments.json +16 -0
- data/static/audited_at.json +1 -0
- data/static/classes.json +18 -0
- data/static/constants.json +4 -0
- data/static/info_arch.json +171 -0
- data/static/previews.json +112 -0
- data/static/statuses.json +1 -0
- metadata +18 -2
@@ -250,7 +250,7 @@ module Primer
|
|
250
250
|
|
251
251
|
private
|
252
252
|
|
253
|
-
def set_action_arguments(system_arguments, scheme: nil
|
253
|
+
def set_action_arguments(system_arguments, scheme: nil)
|
254
254
|
system_arguments[:ml] ||= 2
|
255
255
|
system_arguments[:display] = [:none, :flex]
|
256
256
|
system_arguments[:size] = :medium
|
@@ -0,0 +1 @@
|
|
1
|
+
.SubHeader{align-items:center;display:grid;flex-wrap:wrap;grid-template-areas:"left middle right" "bottom bottom bottom";grid-template-columns:auto 1fr auto;margin-bottom:16px}.SubHeader-rightPane{align-items:center;column-gap:12px;display:flex;grid-area:right}.SubHeader-middlePane{grid-area:middle;text-align:center}.SubHeader-bottomPane{grid-area:bottom}.SubHeader-leftPane{align-items:center;display:flex;gap:12px;grid-area:left;width:100%}.SubHeader-filterContainer{display:flex;gap:8px;width:100%}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["sub_header.pcss"],"names":[],"mappings":"AAEA,WAII,kBAAmB,CAHnB,YAAa,CAOb,cAAe,CANf,8DAA+D,CAC/D,mCAAoC,CAEpC,kBAIJ,CAEA,qBAGI,kBAAmB,CACnB,eAAgB,CAFhB,YAAa,CADb,eAIJ,CAEA,sBACI,gBAAiB,CACjB,iBACJ,CAEA,sBACI,gBACJ,CAEA,oBAGI,kBAAmB,CADnB,YAAa,CAGb,QAAS,CAJT,cAAe,CAGf,UAEJ,CAEA,2BACI,YAAa,CAEb,OAAQ,CADR,UAEJ","file":"sub_header.css","sourcesContent":["/* CSS for SubHeader */\n\n.SubHeader {\n display: grid;\n grid-template-areas: \"left middle right\" \"bottom bottom bottom\";\n grid-template-columns: auto 1fr auto;\n align-items: center;\n margin-bottom: 16px;\n\n /* When the filter input is expanded in mobile, we switch to a flex layout */\n flex-wrap: wrap;\n}\n\n.SubHeader-rightPane {\n grid-area: right;\n display: flex;\n align-items: center;\n column-gap: 12px;\n}\n\n.SubHeader-middlePane {\n grid-area: middle;\n text-align: center;\n}\n\n.SubHeader-bottomPane {\n grid-area: bottom;\n}\n\n.SubHeader-leftPane {\n grid-area: left;\n display: flex;\n align-items: center;\n width: 100%;\n gap: 12px;\n}\n\n.SubHeader-filterContainer {\n display: flex;\n width: 100%;\n gap: 8px;\n}\n"]}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
2
|
+
<div class="SubHeader-leftPane">
|
3
|
+
<%= render @filter_container do %>
|
4
|
+
<%= filter_input %>
|
5
|
+
<%= render @mobile_filter_cancel do
|
6
|
+
I18n.t("button_cancel")
|
7
|
+
end if @mobile_filter_cancel.present? %>
|
8
|
+
<% end if filter_input.present? %>
|
9
|
+
<%= render @mobile_filter_trigger if @mobile_filter_trigger.present? %>
|
10
|
+
<%= filter_button %>
|
11
|
+
</div>
|
12
|
+
<div class="SubHeader-middlePane" data-targets="<%= HIDDEN_FILTER_TARGET_SELECTOR %>">
|
13
|
+
<%= text %>
|
14
|
+
</div>
|
15
|
+
<div class="SubHeader-rightPane" data-targets="<%= HIDDEN_FILTER_TARGET_SELECTOR %>">
|
16
|
+
<% actions.each do |action| %>
|
17
|
+
<%= action %>
|
18
|
+
<% end %>
|
19
|
+
</div>
|
20
|
+
<% if bottom_pane_component.present? %>
|
21
|
+
<div class="SubHeader-bottomPane">
|
22
|
+
<%= bottom_pane_component %>
|
23
|
+
</div>
|
24
|
+
<% end %>
|
25
|
+
<% end %>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
/* CSS for SubHeader */
|
2
|
+
|
3
|
+
.SubHeader {
|
4
|
+
display: grid;
|
5
|
+
grid-template-areas: "left middle right" "bottom bottom bottom";
|
6
|
+
grid-template-columns: auto 1fr auto;
|
7
|
+
align-items: center;
|
8
|
+
margin-bottom: 16px;
|
9
|
+
|
10
|
+
/* When the filter input is expanded in mobile, we switch to a flex layout */
|
11
|
+
flex-wrap: wrap;
|
12
|
+
}
|
13
|
+
|
14
|
+
.SubHeader-rightPane {
|
15
|
+
grid-area: right;
|
16
|
+
display: flex;
|
17
|
+
align-items: center;
|
18
|
+
column-gap: 12px;
|
19
|
+
}
|
20
|
+
|
21
|
+
.SubHeader-middlePane {
|
22
|
+
grid-area: middle;
|
23
|
+
text-align: center;
|
24
|
+
}
|
25
|
+
|
26
|
+
.SubHeader-bottomPane {
|
27
|
+
grid-area: bottom;
|
28
|
+
}
|
29
|
+
|
30
|
+
.SubHeader-leftPane {
|
31
|
+
grid-area: left;
|
32
|
+
display: flex;
|
33
|
+
align-items: center;
|
34
|
+
width: 100%;
|
35
|
+
gap: 12px;
|
36
|
+
}
|
37
|
+
|
38
|
+
.SubHeader-filterContainer {
|
39
|
+
display: flex;
|
40
|
+
width: 100%;
|
41
|
+
gap: 8px;
|
42
|
+
}
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module OpenProject
|
5
|
+
# The SubHeader contains specific actions to modify the page content below, e.g a filter button or a create button
|
6
|
+
# It should not be used stand alone, but in combination with a PageHeader, either as a direct sibling or as part of a tab content
|
7
|
+
class SubHeader < Primer::Component
|
8
|
+
status :open_project
|
9
|
+
|
10
|
+
HIDDEN_FILTER_TARGET_SELECTOR = "sub-header.hiddenItemsOnExpandedFilter"
|
11
|
+
SHOWN_FILTER_TARGET_SELECTOR = "sub-header.shownItemsOnExpandedFilter"
|
12
|
+
|
13
|
+
# A button or custom content that will render on the right-hand side of the component.
|
14
|
+
#
|
15
|
+
# To render a button, call the `with_button` method, which accepts the arguments accepted by <%= link_to_component(Primer::Beta::Button) %>.
|
16
|
+
#
|
17
|
+
# To render custom content, call the `with_button_component` method and pass a block that returns HTML.
|
18
|
+
renders_many :actions, types: {
|
19
|
+
button: {
|
20
|
+
renders: lambda { |icon: nil, **kwargs|
|
21
|
+
if icon
|
22
|
+
Primer::Beta::IconButton.new(icon: icon, **kwargs)
|
23
|
+
else
|
24
|
+
Primer::Beta::Button.new(**kwargs)
|
25
|
+
end
|
26
|
+
},
|
27
|
+
},
|
28
|
+
component: {
|
29
|
+
# A generic slot to render whatever component you like on the right side
|
30
|
+
renders: lambda { |**kwargs|
|
31
|
+
deny_tag_argument(**kwargs)
|
32
|
+
kwargs[:tag] = :div
|
33
|
+
Primer::BaseComponent.new(**kwargs)
|
34
|
+
},
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
renders_one :filter_input, lambda { |name:, label:, **system_arguments|
|
39
|
+
system_arguments[:classes] = class_names(
|
40
|
+
system_arguments[:classes],
|
41
|
+
"SubHeader-filterInput"
|
42
|
+
)
|
43
|
+
system_arguments[:placeholder] ||= I18n.t("button_filter")
|
44
|
+
system_arguments[:leading_visual] ||= { icon: :search }
|
45
|
+
system_arguments[:visually_hide_label] ||= true
|
46
|
+
|
47
|
+
system_arguments[:data] ||= {}
|
48
|
+
system_arguments[:data][:target]= "sub-header.filterInput"
|
49
|
+
|
50
|
+
|
51
|
+
@mobile_filter_trigger = Primer::Beta::IconButton.new(icon: system_arguments[:leading_visual][:icon],
|
52
|
+
display: [:inline_flex, :none],
|
53
|
+
aria: {label: label },
|
54
|
+
"data-action": "click:sub-header#expandFilterInput",
|
55
|
+
"data-targets": HIDDEN_FILTER_TARGET_SELECTOR)
|
56
|
+
|
57
|
+
@mobile_filter_cancel = Primer::Beta::Button.new(scheme: :invisible,
|
58
|
+
display: :none,
|
59
|
+
data: {
|
60
|
+
targets: SHOWN_FILTER_TARGET_SELECTOR,
|
61
|
+
action: "click:sub-header#collapseFilterInput"})
|
62
|
+
|
63
|
+
|
64
|
+
Primer::Alpha::TextField.new(name: name, label: label, **system_arguments)
|
65
|
+
}
|
66
|
+
|
67
|
+
|
68
|
+
# A button or custom content that will render on the left-hand side of the component, next to the filter input.
|
69
|
+
#
|
70
|
+
# To render a button, call the `with_filter_button` method, which accepts the arguments accepted by <%= link_to_component(Primer::Beta::Button) %>.
|
71
|
+
#
|
72
|
+
# To render custom content, call the `with_filter_component` method and pass a block that returns HTML.
|
73
|
+
renders_one :filter_button, types: {
|
74
|
+
button: {
|
75
|
+
renders: lambda { |icon: nil, **kwargs|
|
76
|
+
kwargs[:classes] = class_names(
|
77
|
+
kwargs[:classes],
|
78
|
+
"SubHeader-filterButton"
|
79
|
+
)
|
80
|
+
kwargs[:data] ||= {}
|
81
|
+
kwargs[:data][:targets] ||= HIDDEN_FILTER_TARGET_SELECTOR
|
82
|
+
|
83
|
+
if icon
|
84
|
+
Primer::Beta::IconButton.new(icon: icon, **kwargs)
|
85
|
+
else
|
86
|
+
Primer::Beta::Button.new(**kwargs)
|
87
|
+
end
|
88
|
+
},
|
89
|
+
|
90
|
+
as: :filter_button
|
91
|
+
},
|
92
|
+
component: {
|
93
|
+
# A generic slot to render a custom filter component
|
94
|
+
renders: lambda { |**kwargs|
|
95
|
+
deny_tag_argument(**kwargs)
|
96
|
+
kwargs[:tag] = :div
|
97
|
+
kwargs[:data] ||= {}
|
98
|
+
kwargs[:data][:targets] ||= HIDDEN_FILTER_TARGET_SELECTOR
|
99
|
+
|
100
|
+
Primer::BaseComponent.new(**kwargs)
|
101
|
+
},
|
102
|
+
|
103
|
+
as: :filter_component
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
renders_one :text, lambda { |**system_arguments|
|
108
|
+
system_arguments[:font_weight] ||= :bold
|
109
|
+
|
110
|
+
Primer::Beta::Text.new(**system_arguments)
|
111
|
+
}
|
112
|
+
|
113
|
+
# A slot for a generic component which will be shown in a second row below the rest, spanning the whole width
|
114
|
+
renders_one :bottom_pane_component, lambda { |**system_arguments|
|
115
|
+
deny_tag_argument(**system_arguments)
|
116
|
+
system_arguments[:tag] = :div
|
117
|
+
system_arguments[:mt] ||= 3
|
118
|
+
|
119
|
+
Primer::BaseComponent.new(**system_arguments)
|
120
|
+
}
|
121
|
+
|
122
|
+
|
123
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
124
|
+
def initialize(**system_arguments)
|
125
|
+
@system_arguments = system_arguments
|
126
|
+
@system_arguments[:tag] = :"sub-header"
|
127
|
+
|
128
|
+
@filter_container = Primer::BaseComponent.new(tag: :div,
|
129
|
+
classes: "SubHeader-filterContainer",
|
130
|
+
display: [:none, :flex],
|
131
|
+
data: { targets: SHOWN_FILTER_TARGET_SELECTOR })
|
132
|
+
|
133
|
+
@system_arguments[:classes] = class_names(
|
134
|
+
"SubHeader",
|
135
|
+
system_arguments[:classes]
|
136
|
+
)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
declare class SubHeaderElement extends HTMLElement {
|
2
|
+
filterInput: HTMLElement;
|
3
|
+
hiddenItemsOnExpandedFilter: HTMLElement[];
|
4
|
+
shownItemsOnExpandedFilter: HTMLElement[];
|
5
|
+
expandFilterInput(): void;
|
6
|
+
collapseFilterInput(): void;
|
7
|
+
}
|
8
|
+
declare global {
|
9
|
+
interface Window {
|
10
|
+
SubHeaderElement: typeof SubHeaderElement;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
export {};
|
@@ -0,0 +1,44 @@
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
6
|
+
};
|
7
|
+
import { controller, target, targets } from '@github/catalyst';
|
8
|
+
let SubHeaderElement = class SubHeaderElement extends HTMLElement {
|
9
|
+
expandFilterInput() {
|
10
|
+
for (const item of this.hiddenItemsOnExpandedFilter) {
|
11
|
+
item.classList.add('d-none');
|
12
|
+
}
|
13
|
+
for (const item of this.shownItemsOnExpandedFilter) {
|
14
|
+
item.classList.remove('d-none');
|
15
|
+
}
|
16
|
+
this.classList.add('d-flex');
|
17
|
+
this.filterInput.focus();
|
18
|
+
}
|
19
|
+
collapseFilterInput() {
|
20
|
+
for (const item of this.hiddenItemsOnExpandedFilter) {
|
21
|
+
item.classList.remove('d-none');
|
22
|
+
}
|
23
|
+
for (const item of this.shownItemsOnExpandedFilter) {
|
24
|
+
item.classList.add('d-none');
|
25
|
+
}
|
26
|
+
this.classList.remove('d-flex');
|
27
|
+
}
|
28
|
+
};
|
29
|
+
__decorate([
|
30
|
+
target
|
31
|
+
], SubHeaderElement.prototype, "filterInput", void 0);
|
32
|
+
__decorate([
|
33
|
+
targets
|
34
|
+
], SubHeaderElement.prototype, "hiddenItemsOnExpandedFilter", void 0);
|
35
|
+
__decorate([
|
36
|
+
targets
|
37
|
+
], SubHeaderElement.prototype, "shownItemsOnExpandedFilter", void 0);
|
38
|
+
SubHeaderElement = __decorate([
|
39
|
+
controller
|
40
|
+
], SubHeaderElement);
|
41
|
+
if (!window.customElements.get('sub-header')) {
|
42
|
+
window.SubHeaderElement = SubHeaderElement;
|
43
|
+
window.customElements.define('sub-header', SubHeaderElement);
|
44
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import {controller, target, targets} from '@github/catalyst'
|
2
|
+
|
3
|
+
@controller
|
4
|
+
class SubHeaderElement extends HTMLElement {
|
5
|
+
@target filterInput: HTMLElement
|
6
|
+
@targets hiddenItemsOnExpandedFilter: HTMLElement[]
|
7
|
+
@targets shownItemsOnExpandedFilter: HTMLElement[]
|
8
|
+
|
9
|
+
expandFilterInput() {
|
10
|
+
for (const item of this.hiddenItemsOnExpandedFilter) {
|
11
|
+
item.classList.add('d-none')
|
12
|
+
}
|
13
|
+
|
14
|
+
for (const item of this.shownItemsOnExpandedFilter) {
|
15
|
+
item.classList.remove('d-none')
|
16
|
+
}
|
17
|
+
|
18
|
+
this.classList.add('d-flex')
|
19
|
+
|
20
|
+
this.filterInput.focus()
|
21
|
+
}
|
22
|
+
|
23
|
+
collapseFilterInput() {
|
24
|
+
for (const item of this.hiddenItemsOnExpandedFilter) {
|
25
|
+
item.classList.remove('d-none')
|
26
|
+
}
|
27
|
+
|
28
|
+
for (const item of this.shownItemsOnExpandedFilter) {
|
29
|
+
item.classList.add('d-none')
|
30
|
+
}
|
31
|
+
|
32
|
+
this.classList.remove('d-flex')
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
declare global {
|
37
|
+
interface Window {
|
38
|
+
SubHeaderElement: typeof SubHeaderElement
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
if (!window.customElements.get('sub-header')) {
|
43
|
+
window.SubHeaderElement = SubHeaderElement
|
44
|
+
window.customElements.define('sub-header', SubHeaderElement)
|
45
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%= render(Primer::OpenProject::SubHeader.new) do |component| %>
|
2
|
+
<% component.with_filter_input(name: "filter", label: "Filter") %>
|
3
|
+
|
4
|
+
<% component.with_action_component do %>
|
5
|
+
<%= render Primer::Alpha::ActionMenu.new(menu_id: "menu-1") do |menu|
|
6
|
+
menu.with_show_button(icon: :"op-kebab-vertical", "aria-label": "Menu")
|
7
|
+
menu.with_item(label: "Subitem 1") do |item|
|
8
|
+
item.with_leading_visual_icon(icon: :paste)
|
9
|
+
end
|
10
|
+
menu.with_item(label: "Subitem 2") do |item|
|
11
|
+
item.with_leading_visual_icon(icon: :log)
|
12
|
+
end
|
13
|
+
end %>
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%= render(Primer::OpenProject::SubHeader.new) do |component| %>
|
2
|
+
<% component.with_filter_input(name: "filter", label: "Filter") %>
|
3
|
+
<% component.with_filter_component do %>
|
4
|
+
<!-- Render any custom filter component that you want -->
|
5
|
+
<%= render(Primer::Beta::IconButton.new(icon: "filter", "aria-label": "Filter")) %>
|
6
|
+
<% end %>
|
7
|
+
<% component.with_bottom_pane_component do %>
|
8
|
+
<!-- Render any custom component that you want -->
|
9
|
+
<!-- The component will be shown in a second row below the rest, spanning the whole width -->
|
10
|
+
<%= render(Primer::BaseComponent.new(tag: :div, bg: :accent, p: 3)) { 'Render any custom content here (e.g a filter area)' } %>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<%= render(Primer::OpenProject::SubHeader.new) do |component| %>
|
2
|
+
<% component.with_filter_input(name: "filter", label: "Filter") %>
|
3
|
+
|
4
|
+
<% component.with_action_component do %>
|
5
|
+
<%= render(Primer::Beta::ButtonGroup.new) do |group|
|
6
|
+
group.with_button { "Button 1" }
|
7
|
+
group.with_button { "Button 2" }
|
8
|
+
group.with_button { "Button 3" }
|
9
|
+
end %>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%= render(Primer::OpenProject::SubHeader.new) do |component| %>
|
2
|
+
<% component.with_filter_input(name: "filter", label: "Filter") %>
|
3
|
+
<% component.with_filter_component do %>
|
4
|
+
<!-- Render any custom filter component that you want -->
|
5
|
+
<!-- Note, that you can pass an ID for the bottom pane if you need to access that area for further filter actions-->
|
6
|
+
<%= render(Primer::Beta::IconButton.new(icon: "filter", "aria-label": "Filter")) %>
|
7
|
+
<% end %>
|
8
|
+
<% end %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%= render(Primer::OpenProject::SubHeader.new) do |component| %>
|
2
|
+
<% component.with_filter_input(name: "filter", label: "Filter") %>
|
3
|
+
|
4
|
+
<% component.with_action_component do %>
|
5
|
+
<%= render(Primer::Alpha::Dialog.new(id: "dialog-one", title: "Dialog")) do |d| %>
|
6
|
+
<% d.with_show_button { "Show Dialog" } %>
|
7
|
+
<% d.with_body do %>
|
8
|
+
Hello world!
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Setup Playground to use all available component props
|
4
|
+
# Setup Features to use individual component props and combinations
|
5
|
+
|
6
|
+
module Primer
|
7
|
+
module OpenProject
|
8
|
+
# @label SubHeader
|
9
|
+
class SubHeaderPreview < ViewComponent::Preview
|
10
|
+
# @label Playground
|
11
|
+
# @param show_filter_input toggle
|
12
|
+
# @param show_filter_button toggle
|
13
|
+
# @param show_action_button toggle
|
14
|
+
# @param text text
|
15
|
+
def playground(show_filter_input: true, show_filter_button: true, show_action_button: true, text: nil)
|
16
|
+
render(Primer::OpenProject::SubHeader.new) do |component|
|
17
|
+
component.with_filter_input(name: "filter", label: "Filter") if show_filter_input
|
18
|
+
component.with_filter_button do |button|
|
19
|
+
button.with_trailing_visual_counter(count: "15")
|
20
|
+
"Filter"
|
21
|
+
end if show_filter_button
|
22
|
+
|
23
|
+
component.with_text { text } unless text.nil?
|
24
|
+
|
25
|
+
component.with_action_button(scheme: :primary) do |button|
|
26
|
+
button.with_leading_visual_icon(icon: :plus)
|
27
|
+
"Create"
|
28
|
+
end if show_action_button
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# @label Default
|
33
|
+
def default
|
34
|
+
render(Primer::OpenProject::SubHeader.new) do |component|
|
35
|
+
component.with_filter_input(name: "filter", label: "Filter")
|
36
|
+
component.with_filter_button do |button|
|
37
|
+
button.with_trailing_visual_counter(count: "15")
|
38
|
+
"Filter"
|
39
|
+
end
|
40
|
+
|
41
|
+
component.with_action_button(scheme: :primary) do |button|
|
42
|
+
button.with_leading_visual_icon(icon: :plus)
|
43
|
+
"Create"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# @label With ActionMenu
|
49
|
+
def action_menu_buttons
|
50
|
+
render_with_template(locals: {})
|
51
|
+
end
|
52
|
+
|
53
|
+
# @label With Dialog
|
54
|
+
def dialog_buttons
|
55
|
+
render_with_template(locals: {})
|
56
|
+
end
|
57
|
+
|
58
|
+
# @label With ButtonGroup
|
59
|
+
def button_group
|
60
|
+
render_with_template(locals: {})
|
61
|
+
end
|
62
|
+
|
63
|
+
# @label With custom filter button
|
64
|
+
def custom_filter_button
|
65
|
+
render_with_template(locals: {})
|
66
|
+
end
|
67
|
+
|
68
|
+
# @label With a custom area below
|
69
|
+
def bottom_pane
|
70
|
+
render_with_template(locals: {})
|
71
|
+
end
|
72
|
+
|
73
|
+
# @label With Text in the middle
|
74
|
+
def text
|
75
|
+
render(Primer::OpenProject::SubHeader.new) do |component|
|
76
|
+
component.with_filter_input(name: "filter", label: "Filter")
|
77
|
+
|
78
|
+
component.with_text { "Hello world!" }
|
79
|
+
|
80
|
+
component.with_action_button(scheme: :primary) do |button|
|
81
|
+
button.with_leading_visual_icon(icon: :plus)
|
82
|
+
"Create"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/static/arguments.json
CHANGED
@@ -5023,6 +5023,22 @@
|
|
5023
5023
|
}
|
5024
5024
|
]
|
5025
5025
|
},
|
5026
|
+
{
|
5027
|
+
"component": "OpenProject::SubHeader",
|
5028
|
+
"status": "open_project",
|
5029
|
+
"a11y_reviewed": false,
|
5030
|
+
"short_name": "OpenProjectSubHeader",
|
5031
|
+
"source": "https://github.com/primer/view_components/tree/main/app/components/primer/open_project/sub_header.rb",
|
5032
|
+
"lookbook": "https://primer.style/view-components/lookbook/inspect/primer/open_project/sub_header/default/",
|
5033
|
+
"parameters": [
|
5034
|
+
{
|
5035
|
+
"name": "system_arguments",
|
5036
|
+
"type": "Hash",
|
5037
|
+
"default": "N/A",
|
5038
|
+
"description": "[System arguments](/system-arguments)"
|
5039
|
+
}
|
5040
|
+
]
|
5041
|
+
},
|
5026
5042
|
{
|
5027
5043
|
"component": "OpenProject::ZenModeButton",
|
5028
5044
|
"status": "open_project",
|
data/static/audited_at.json
CHANGED
@@ -123,6 +123,7 @@
|
|
123
123
|
"Primer::OpenProject::PageHeader": "",
|
124
124
|
"Primer::OpenProject::PageHeader::Dialog": "",
|
125
125
|
"Primer::OpenProject::PageHeader::Menu": "",
|
126
|
+
"Primer::OpenProject::SubHeader": "",
|
126
127
|
"Primer::OpenProject::ZenModeButton": "",
|
127
128
|
"Primer::Tooltip": "",
|
128
129
|
"Primer::Truncate": ""
|
data/static/classes.json
CHANGED
@@ -555,6 +555,24 @@
|
|
555
555
|
"State--small": [
|
556
556
|
"Primer::Beta::State"
|
557
557
|
],
|
558
|
+
"SubHeader": [
|
559
|
+
"Primer::OpenProject::SubHeader"
|
560
|
+
],
|
561
|
+
"SubHeader-bottomPane": [
|
562
|
+
"Primer::OpenProject::SubHeader"
|
563
|
+
],
|
564
|
+
"SubHeader-filterContainer": [
|
565
|
+
"Primer::OpenProject::SubHeader"
|
566
|
+
],
|
567
|
+
"SubHeader-leftPane": [
|
568
|
+
"Primer::OpenProject::SubHeader"
|
569
|
+
],
|
570
|
+
"SubHeader-middlePane": [
|
571
|
+
"Primer::OpenProject::SubHeader"
|
572
|
+
],
|
573
|
+
"SubHeader-rightPane": [
|
574
|
+
"Primer::OpenProject::SubHeader"
|
575
|
+
],
|
558
576
|
"Subhead": [
|
559
577
|
"Primer::Beta::Subhead"
|
560
578
|
],
|
data/static/constants.json
CHANGED
@@ -1473,6 +1473,10 @@
|
|
1473
1473
|
},
|
1474
1474
|
"Primer::OpenProject::PageHeader::Menu": {
|
1475
1475
|
},
|
1476
|
+
"Primer::OpenProject::SubHeader": {
|
1477
|
+
"HIDDEN_FILTER_TARGET_SELECTOR": "sub-header.hiddenItemsOnExpandedFilter",
|
1478
|
+
"SHOWN_FILTER_TARGET_SELECTOR": "sub-header.shownItemsOnExpandedFilter"
|
1479
|
+
},
|
1476
1480
|
"Primer::OpenProject::ZenModeButton": {
|
1477
1481
|
"ZEN_MODE_BUTTON_ICON": "screen-full",
|
1478
1482
|
"ZEN_MODE_BUTTON_LABEL": "Translation missing: en.label_zen_mode"
|