Skip to content

Commit

Permalink
Add GridLayout Component
Browse files Browse the repository at this point in the history
  • Loading branch information
HDinger committed Oct 6, 2023
1 parent 92f2d85 commit fa3d99c
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 3 deletions.
5 changes: 3 additions & 2 deletions .changeset/hip-dancers-march.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
'@openproject/primer-view-components': minor
---

Add FlexLayout Component
- Add FlexLayout Component
- Add GridLayout Component

<!-- Changed components: Primer::OpenProject::FlexLayout -->
<!-- Changed components: Primer::OpenProject::FlexLayout, Primer::OpenProject::GridLayout -->
11 changes: 11 additions & 0 deletions app/components/primer/open_project/grid_layout.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<% if @system_arguments[:tag] %>
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
<% areas.each do |row| %>
<%= row %>
<% end %>
<% end %>
<% else %>
<% areas.each do |row| %>
<%= row %>
<% end %>
<% end %>
33 changes: 33 additions & 0 deletions app/components/primer/open_project/grid_layout.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

module Primer
module OpenProject
# A layouting component used to arrange multiple components in a CSS Grid
class GridLayout < Primer::Component
status :open_project
attr_reader :css_class

renders_many :areas, lambda { |area_name, component = ::Primer::BaseComponent, **system_arguments, &block|
render(Primer::OpenProject::GridLayout::Area.new(@css_class, area_name, component, **system_arguments), &block)
}

# @param css_class [String] The basic css class applied on the grid-container
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
def initialize(css_class:, **system_arguments)
super

@css_class = css_class
@system_arguments = system_arguments
#@system_arguments[:display] = :grid

Check failure on line 21 in app/components/primer/open_project/grid_layout.rb

View workflow job for this annotation

GitHub Actions / rubocop

Layout/LeadingCommentSpace: Missing space after `#`.
@system_arguments[:classes] = class_names(
@system_arguments[:classes],
css_class
)
end

def render?
areas.any?
end
end
end
end
38 changes: 38 additions & 0 deletions app/components/primer/open_project/grid_layout/area.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

module Primer
module OpenProject
class GridLayout
# GridLayout::Area is an internal component that wraps the items in a div with the given new class and responding "grid-area"
class Area < Primer::Component
status :open_project

DEFAULT_TAG = :div
TAG_OPTIONS = [DEFAULT_TAG, :span].freeze

# @param css_class [String] The basic css class applied on the grid-container
# @param area_name [Symbol] The specific area name, used for creating the element class and the "grid-area" style
# @param component [ViewComponent::Base] The instance of the component to be rendered.
# @param tag [Symbol] <%= one_of(Primer::OpenProject::GridLayout::TAG_OPTIONS) %>
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
def initialize(css_class, area_name, component = ::Primer::BaseComponent, tag: DEFAULT_TAG, **system_arguments)
@component = component
@system_arguments = system_arguments
@styles = [
"grid-area: #{area_name}"
]
@system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
@system_arguments[:style] = join_style_arguments(@system_arguments[:style], *@styles)
@system_arguments[:classes] = class_names(
@system_arguments[:classes],
"#{css_class}--#{area_name}"
)
end

def call
render(@component.new(**@system_arguments)) { content }
end
end
end
end
end
37 changes: 37 additions & 0 deletions previews/primer/open_project/grid_layout_preview.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# 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 GridLayout
class GridLayoutPreview < ViewComponent::Preview
# @label Playground
def playground
render(Primer::OpenProject::GridLayout.new(css_class: "grid-layout", tag: :div)) do |component|
component.with_area(:area1, bg: :attention, p: 6) do
"Block 1"
end
component.with_area(:area2, bg: :accent, p: 6) do
"Block 2"
end
end
end

# The component can be used for easy layouting of multiple child components.
# The component sets classes as well the grid-area definitions. The actual grid template can then be defined a separate CSS file.
# @label Default
def default
render(Primer::OpenProject::GridLayout.new(css_class: "grid-layout", tag: :div)) do |component|
component.with_area(:area1, bg: :attention, p: 6) do
"Block 1"
end
component.with_area(:area2, bg: :accent, p: 6) do
"Block 2"
end
end
end
end
end
end
8 changes: 7 additions & 1 deletion test/components/component_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ class PrimerComponentTest < Minitest::Test

# Components with any arguments necessary to make them render
COMPONENTS_WITH_ARGS = [
[Primer::OpenProject::GridLayout, { css_class: "grid-layout", tag: :div }, proc { |component|
component.with_area(:area) do
"Foo"
end
}],
[Primer::OpenProject::FlexLayout, {}, proc { |component|
component.with_row { "Foo" }
}],
Expand Down Expand Up @@ -161,7 +166,8 @@ def test_registered_components
"Primer::Component",
"Primer::Content",
"Primer::Navigation::TabComponent",
"Primer::OpenProject::BorderGrid::Cell"
"Primer::OpenProject::BorderGrid::Cell",
"Primer::OpenProject::GridLayout::Area"
]

primer_component_files_count = Dir["app/components/**/*.rb"].count { |p| p.exclude?("/experimental/") }
Expand Down
13 changes: 13 additions & 0 deletions test/components/primer/open_project/grid_layout/area_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

require "components/test_helper"

class PrimerOpenProjectGridLayoutAreaTest < Minitest::Test
include Primer::ComponentTestHelpers

def test_renders
render_inline(Primer::OpenProject::GridLayout::Area.new("grid-layout", "area"))

assert_selector(".grid-layout--area[style='grid-area: area']")
end
end
28 changes: 28 additions & 0 deletions test/components/primer/open_project/grid_layout_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

require "components/test_helper"

class PrimerOpenProjectGridLayoutTest < Minitest::Test
include Primer::ComponentTestHelpers

def test_renders
render_inline(Primer::OpenProject::GridLayout.new(css_class: "grid-layout", tag: :div)) do |component|
component.with_area(:area1) do
"Block 1"
end
component.with_area(:area2) do
"Block 2"
end
end

assert_selector(".grid-layout")
assert_selector(".grid-layout--area1[style='grid-area: area1']")
assert_selector(".grid-layout--area2[style='grid-area: area2']")
end

def test_does_not_render_with_no_area_provided
render_inline(Primer::OpenProject::GridLayout.new(css_class: "grid-layout", tag: :div))

refute_component_rendered
end
end
11 changes: 11 additions & 0 deletions test/system/open_project/grid_layout_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

require "system/test_case"

class IntegrationOpenProjectGridLayoutTest < System::TestCase
def test_renders_component
visit_preview(:default)

assert_selector(".grid-layout")
end
end

0 comments on commit fa3d99c

Please sign in to comment.