diff --git a/.changeset/lucky-rules-suffer.md b/.changeset/lucky-rules-suffer.md new file mode 100644 index 0000000000..d2aa4a9637 --- /dev/null +++ b/.changeset/lucky-rules-suffer.md @@ -0,0 +1,7 @@ +--- +'@openproject/primer-view-components': minor +--- + +Add BorderGrid Component + + diff --git a/app/components/primer/open_project/border_grid.html.erb b/app/components/primer/open_project/border_grid.html.erb new file mode 100644 index 0000000000..60a50cef79 --- /dev/null +++ b/app/components/primer/open_project/border_grid.html.erb @@ -0,0 +1,7 @@ +<%= render Primer::BaseComponent.new(**@system_arguments) do %> + <% rows.each do |row| %> + <%= render Primer::BaseComponent.new(tag: :div, classes: "BorderGrid-row") do %> + <%= row %> + <% end %> + <% end %> +<% end %> diff --git a/app/components/primer/open_project/border_grid.pcss b/app/components/primer/open_project/border_grid.pcss new file mode 100644 index 0000000000..ef6205a550 --- /dev/null +++ b/app/components/primer/open_project/border_grid.pcss @@ -0,0 +1,35 @@ +/* CSS for BorderGrid */ + +.BorderGrid { + display: table; + width: 100%; + margin-top: -16px; + margin-bottom: -16px; + table-layout: fixed; + border-collapse: collapse; + border-style: hidden +} + +.BorderGrid .BorderGrid-cell { + padding-top: 16px; + padding-bottom: 16px +} + +.BorderGrid--spacious { + margin-top: -24px; + margin-bottom: -24px +} + +.BorderGrid--spacious .BorderGrid-cell { + padding-top: 24px; + padding-bottom: 24px +} + +.BorderGrid-row { + display: table-row +} + +.BorderGrid-cell { + display: table-cell; + border: 1px solid var(--color-border-muted) +} diff --git a/app/components/primer/open_project/border_grid.rb b/app/components/primer/open_project/border_grid.rb new file mode 100644 index 0000000000..fdec01c669 --- /dev/null +++ b/app/components/primer/open_project/border_grid.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Primer + module OpenProject + # A set of blocks that are shown below each other with separator lines in between + class BorderGrid < Primer::Component + status :open_project + + # Use to render a block inside the grid + # + # @param system_arguments [Hash] <%= link_to_system_arguments_docs %> + renders_many :rows, lambda { |**system_arguments| + Primer::OpenProject::BorderGrid::Cell.new(**system_arguments) + } + + + # @param spacious [Boolean] Whether to add margin to the bottom of the component. + # @param system_arguments [Hash] <%= link_to_system_arguments_docs %> + def initialize(spacious: false, **system_arguments) + @system_arguments = system_arguments + @system_arguments[:tag] = "div" + @spacious = spacious + + @system_arguments[:classes] = + class_names( + @system_arguments[:classes], + "BorderGrid", + "BorderGrid--spacious" => @spacious + ) + end + + def render? + rows.any? + end + end + end +end diff --git a/app/components/primer/open_project/border_grid/cell.html.erb b/app/components/primer/open_project/border_grid/cell.html.erb new file mode 100644 index 0000000000..7e7bfce0ea --- /dev/null +++ b/app/components/primer/open_project/border_grid/cell.html.erb @@ -0,0 +1,3 @@ +<%= render Primer::BaseComponent.new(**@system_arguments) do %> + <%= content %> +<% end %> diff --git a/app/components/primer/open_project/border_grid/cell.rb b/app/components/primer/open_project/border_grid/cell.rb new file mode 100644 index 0000000000..b8454b52b0 --- /dev/null +++ b/app/components/primer/open_project/border_grid/cell.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Primer + module OpenProject + # A single cell inside the BorderGrid + # A cell can contain for example an action list or a status badge + class BorderGrid::Cell < Primer::Component + status :open_project + + # @param system_arguments [Hash] <%= link_to_system_arguments_docs %> + def initialize(**system_arguments) + @system_arguments = system_arguments + @system_arguments[:tag] = "div" + + @system_arguments[:classes] = + class_names( + @system_arguments[:classes], + "BorderGrid-cell", + ) + end + end + end +end diff --git a/app/components/primer/primer.pcss b/app/components/primer/primer.pcss index 19651f979f..660e69f718 100644 --- a/app/components/primer/primer.pcss +++ b/app/components/primer/primer.pcss @@ -44,3 +44,4 @@ /* OP specifics */ @import "./open_project/page_header.pcss"; @import "./open_project/drag_handle.pcss"; +@import "./open_project/border_grid.pcss"; diff --git a/previews/primer/open_project/border_grid_preview.rb b/previews/primer/open_project/border_grid_preview.rb new file mode 100644 index 0000000000..8bd101a09e --- /dev/null +++ b/previews/primer/open_project/border_grid_preview.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +# Setup Playground to use all available component props +# Setup Features to use individual component props and combinations + +module Primer + module OpenProject + # @label BorderGrid + class BorderGridPreview < ViewComponent::Preview + + # @label Playground + # @param spacious [Boolean] toggle + def playground(spacious: false) + render(Primer::OpenProject::BorderGrid.new(spacious: spacious)) do |grid| + grid.with_row { "Block 1" } + grid.with_row { "Block 2" } + grid.with_row { "Block 3" } + end + end + + # @label Default Options + # + # @snapshot + def default() + render(Primer::OpenProject::BorderGrid.new) do |grid| + grid.with_row { "Block 1" } + grid.with_row { "Block 2" } + grid.with_row { "Block 3" } + end + end + end + end +end diff --git a/static/classes.json b/static/classes.json index 6dce96467f..ddae4c7083 100644 --- a/static/classes.json +++ b/static/classes.json @@ -101,6 +101,18 @@ "Banner": [ "Primer::Alpha::Banner" ], + "BorderGrid": [ + "Primer::OpenProject::BorderGrid" + ], + "BorderGrid--spacious": [ + "Primer::OpenProject::BorderGrid" + ], + "BorderGrid-cell": [ + "Primer::OpenProject::BorderGrid" + ], + "BorderGrid-row": [ + "Primer::OpenProject::BorderGrid" + ], "Box": [ "Primer::Beta::BorderBox" ], diff --git a/test/components/component_test.rb b/test/components/component_test.rb index f389cc5f7e..8a8d413f72 100644 --- a/test/components/component_test.rb +++ b/test/components/component_test.rb @@ -9,6 +9,9 @@ class PrimerComponentTest < Minitest::Test # Components with any arguments necessary to make them render COMPONENTS_WITH_ARGS = [ [Primer::OpenProject::DragHandle, {}], + [Primer::OpenProject::BorderGrid, {}, proc { |component| + component.with_row { "Foo" } + }], [Primer::OpenProject::PageHeader, {}, proc { |component| component.with_title { "Foo" } }], @@ -149,7 +152,8 @@ def test_registered_components "Primer::Alpha::OcticonSymbols", "Primer::Component", "Primer::Content", - "Primer::Navigation::TabComponent" + "Primer::Navigation::TabComponent", + "Primer::OpenProject::BorderGrid::Cell" ] primer_component_files_count = Dir["app/components/**/*.rb"].count { |p| p.exclude?("/experimental/") } diff --git a/test/components/primer/open_project/border_grid/cell_test.rb b/test/components/primer/open_project/border_grid/cell_test.rb new file mode 100644 index 0000000000..b70b3f5ce1 --- /dev/null +++ b/test/components/primer/open_project/border_grid/cell_test.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require "components/test_helper" + +class PrimerOpenProjectBorderGridCellTest < Minitest::Test + include Primer::ComponentTestHelpers + + def test_renders + render_inline(Primer::OpenProject::BorderGrid::Cell.new) + + assert_selector(".BorderGrid-cell") + end +end diff --git a/test/components/primer/open_project/border_grid_test.rb b/test/components/primer/open_project/border_grid_test.rb new file mode 100644 index 0000000000..cde24e1edb --- /dev/null +++ b/test/components/primer/open_project/border_grid_test.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require "components/test_helper" + +class PrimerOpenProjectBorderGridTest < Minitest::Test + include Primer::ComponentTestHelpers + + def test_renders + render_inline(Primer::OpenProject::BorderGrid.new) do |grid| + grid.with_row { "Block 1" } + grid.with_row { "Block 2" } + grid.with_row { "Block 3" } + end + + assert_selector(".BorderGrid") + assert_selector(".BorderGrid-row", count: 3) + assert_selector(".BorderGrid-row .BorderGrid-cell", text: "Block 1") + end + + def test_renders_spacious + render_inline(Primer::OpenProject::BorderGrid.new(spacious: true)) do |grid| + grid.with_row { "Block 1" } + grid.with_row { "Block 2" } + grid.with_row { "Block 3" } + end + + assert_selector(".BorderGrid.BorderGrid--spacious") + end +end diff --git a/test/system/open_project/border_grid_test.rb b/test/system/open_project/border_grid_test.rb new file mode 100644 index 0000000000..5f2a3a16cb --- /dev/null +++ b/test/system/open_project/border_grid_test.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require "system/test_case" + +class IntegrationOpenProjectBorderGridTest < System::TestCase + def test_renders_component + visit_preview(:default) + + assert_selector(".BorderGrid") + end +end