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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/app/assets/javascripts/app/components/primer/open_project/sub_header_element.d.ts +13 -0
  4. data/app/assets/javascripts/app/components/primer/primer.d.ts +1 -0
  5. data/app/assets/javascripts/primer_view_components.js +1 -1
  6. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  7. data/app/assets/styles/primer_view_components.css +1 -1
  8. data/app/assets/styles/primer_view_components.css.map +1 -1
  9. data/app/components/primer/open_project/page_header.rb +1 -1
  10. data/app/components/primer/open_project/sub_header.css +1 -0
  11. data/app/components/primer/open_project/sub_header.css.json +11 -0
  12. data/app/components/primer/open_project/sub_header.css.map +1 -0
  13. data/app/components/primer/open_project/sub_header.html.erb +25 -0
  14. data/app/components/primer/open_project/sub_header.pcss +42 -0
  15. data/app/components/primer/open_project/sub_header.rb +140 -0
  16. data/app/components/primer/open_project/sub_header_element.d.ts +13 -0
  17. data/app/components/primer/open_project/sub_header_element.js +44 -0
  18. data/app/components/primer/open_project/sub_header_element.ts +45 -0
  19. data/app/components/primer/primer.d.ts +1 -0
  20. data/app/components/primer/primer.js +1 -0
  21. data/app/components/primer/primer.pcss +1 -0
  22. data/app/components/primer/primer.ts +1 -0
  23. data/lib/primer/view_components/version.rb +2 -2
  24. data/previews/primer/open_project/sub_header_preview/action_menu_buttons.html.erb +15 -0
  25. data/previews/primer/open_project/sub_header_preview/bottom_pane.html.erb +12 -0
  26. data/previews/primer/open_project/sub_header_preview/button_group.html.erb +11 -0
  27. data/previews/primer/open_project/sub_header_preview/custom_filter_button.html.erb +8 -0
  28. data/previews/primer/open_project/sub_header_preview/dialog_buttons.html.erb +12 -0
  29. data/previews/primer/open_project/sub_header_preview.rb +88 -0
  30. data/static/arguments.json +16 -0
  31. data/static/audited_at.json +1 -0
  32. data/static/classes.json +18 -0
  33. data/static/constants.json +4 -0
  34. data/static/info_arch.json +171 -0
  35. data/static/previews.json +112 -0
  36. data/static/statuses.json +1 -0
  37. 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, button_action: false)
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,11 @@
1
+ {
2
+ "name": "open_project/sub_header",
3
+ "selectors": [
4
+ ".SubHeader",
5
+ ".SubHeader-rightPane",
6
+ ".SubHeader-middlePane",
7
+ ".SubHeader-bottomPane",
8
+ ".SubHeader-leftPane",
9
+ ".SubHeader-filterContainer"
10
+ ]
11
+ }
@@ -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
+ }
@@ -24,3 +24,4 @@ import '../../../lib/primer/forms/toggle_switch_input';
24
24
  import './alpha/action_menu/action_menu_element';
25
25
  import './open_project/page_header_element';
26
26
  import './open_project/zen_mode_button';
27
+ import './open_project/sub_header_element';
@@ -24,3 +24,4 @@ import '../../../lib/primer/forms/toggle_switch_input';
24
24
  import './alpha/action_menu/action_menu_element';
25
25
  import './open_project/page_header_element';
26
26
  import './open_project/zen_mode_button';
27
+ import './open_project/sub_header_element';
@@ -44,3 +44,4 @@
44
44
  @import "./open_project/drag_handle.pcss";
45
45
  @import "./open_project/border_grid.pcss";
46
46
  @import "./open_project/input_group.pcss";
47
+ @import "./open_project/sub_header.pcss";
@@ -24,3 +24,4 @@ import '../../../lib/primer/forms/toggle_switch_input'
24
24
  import './alpha/action_menu/action_menu_element'
25
25
  import './open_project/page_header_element'
26
26
  import './open_project/zen_mode_button'
27
+ import './open_project/sub_header_element'
@@ -5,8 +5,8 @@ module Primer
5
5
  module ViewComponents
6
6
  module VERSION
7
7
  MAJOR = 0
8
- MINOR = 31
9
- PATCH = 0
8
+ MINOR = 32
9
+ PATCH = 1
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
@@ -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
@@ -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",
@@ -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
  ],
@@ -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"