openproject-primer_view_components 0.31.0 → 0.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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"
|