Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions Sources/Ignite/Elements/Grid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,50 +28,78 @@ public struct Grid: HTML, HorizontalAligning {
/// The amount of space between elements.
private var spacingAmount: SpacingType = .semantic(.none)

/// The alignment of the items within the grid.
private var alignment: Alignment = .center

/// The items to display in this grid.
private var items: HTMLCollection

/// Creates a new `Grid` object using a block element builder
/// that returns an array of items to use in this grid.
/// - Parameters:
/// - alignment: The alignment of items in the grid. Defaults to `.center`.
/// - spacing: The number of pixels between each element.
/// - items: The items to use in this grid.
public init(spacing: Int, @HTMLBuilder items: () -> some HTML) {
public init(
alignment: Alignment = .center,
spacing: Int,
@HTMLBuilder items: () -> some HTML
) {
self.items = HTMLCollection(items)
self.alignment = alignment
self.spacingAmount = .exact(spacing)
}

/// Creates a new `Grid` object using a block element builder
/// that returns an array of items to use in this grid.
/// - Parameters:
/// - alignment: The alignment of items in the grid. Defaults to `.center`.
/// - spacing: The predefined size between each element. Defaults to `.none`.
/// - items: The items to use in this grid.
public init(spacing: SpacingAmount = .medium, @HTMLBuilder items: () -> some HTML) {
public init(
alignment: Alignment = .center,
spacing: SpacingAmount = .medium,
@HTMLBuilder items: () -> some HTML
) {
self.items = HTMLCollection(items)
self.alignment = alignment
self.spacingAmount = .semantic(spacing)
}

/// Creates a new grid from a collection of items, along with a function that converts
/// a single object from the collection into one grid column.
/// - Parameters:
/// - items: A sequence of items you want to convert into columns.
/// - alignment: The alignment of items in the grid. Defaults to `.center`.
/// - spacing: The number of pixels between each element.
/// - content: A function that accepts a single value from the sequence, and
/// returns a some HTML representing that value in the grid.
public init<T>(_ items: any Sequence<T>, spacing: Int, content: (T) -> some HTML) {
public init<T>(
_ items: any Sequence<T>,
alignment: Alignment = .center,
spacing: Int, content: (T) -> some HTML
) {
self.items = HTMLCollection(items.map(content))
self.alignment = alignment
self.spacingAmount = .exact(spacing)
}

/// Creates a new grid from a collection of items, along with a function that converts
/// a single object from the collection into one grid column.
/// - Parameters:
/// - items: A sequence of items you want to convert into columns.
/// - alignment: The alignment of items in the grid. Defaults to `.center`.
/// - spacing: The predefined size between each element. Defaults to `.none`
/// - content: A function that accepts a single value from the sequence, and
/// returns a some HTML representing that value in the grid.
public init<T>(_ items: any Sequence<T>, spacing: SpacingAmount = .medium, content: (T) -> some HTML) {
public init<T>(
_ items: any Sequence<T>,
alignment: Alignment = .center,
spacing: SpacingAmount = .medium,
content: (T) -> some HTML
) {
self.items = HTMLCollection(items.map(content))
self.alignment = alignment
self.spacingAmount = .semantic(spacing)
}

Expand All @@ -88,6 +116,7 @@ public struct Grid: HTML, HorizontalAligning {
/// - Returns: The HTML for this element.
public func render() -> String {
var gridAttributes = attributes.appending(classes: ["row"])
gridAttributes.append(classes: alignment.horizontal.containerAlignmentClass)

// If a column count is set, we want to use that for all
// page sizes that are medium and above. Below that we
Expand Down Expand Up @@ -138,6 +167,7 @@ public struct Grid: HTML, HorizontalAligning {

return Section(item)
.class(name ?? "col")
.class(alignment.vertical.itemAlignmentClass)
}

/// Renders a group of HTML elements with consistent styling and attributes.
Expand Down
11 changes: 0 additions & 11 deletions Sources/Ignite/Elements/HStack.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,3 @@ public struct HStack: HTML {
return "<div\(attributes)>\(content)</div>"
}
}

private extension VerticalAlignment {
/// The Bootstrap alignment class for items within a flexbox
var itemAlignmentClass: String {
switch self {
case .top: "align-self-start"
case .center: "align-self-center"
case .bottom: "align-self-end"
}
}
}
2 changes: 1 addition & 1 deletion Sources/Ignite/Modifiers/HorizontalAlignment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public enum HorizontalAlignment: String, Sendable, Equatable {
case trailing = "text-end"

/// The Bootstrap class for flex justify-content alignment
var flexAlignmentClass: String {
var containerAlignmentClass: String {
switch self {
case .leading: "justify-content-start"
case .center: "justify-content-center"
Expand Down
2 changes: 1 addition & 1 deletion Sources/Ignite/Types/Alignment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public struct Alignment: Equatable {
extension Alignment {
/// The appropriate Bootstrap classes for this alignment
var bootstrapClasses: [String] {
[horizontal.flexAlignmentClass, vertical.flexAlignmentClass]
[horizontal.containerAlignmentClass, vertical.containerAlignmentClass]
}

/// Flex container rules for aligning content
Expand Down
13 changes: 11 additions & 2 deletions Sources/Ignite/Types/VerticalAlignment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,21 @@ public enum VerticalAlignment: Equatable, Sendable {
/// Align content to the bottom
case bottom

/// The Bootstrap class that implements this alignment
var flexAlignmentClass: String {
/// The Bootstrap class for the container with this alignment
var containerAlignmentClass: String {
switch self {
case .top: "align-items-start"
case .center: "align-items-center"
case .bottom: "align-items-end"
}
}

/// The Bootstrap class applied to items inside a container
var itemAlignmentClass: String {
switch self {
case .top: "align-self-start"
case .center: "align-self-center"
case .bottom: "align-self-end"
}
}
}
36 changes: 18 additions & 18 deletions Tests/IgniteTesting/Elements/Grid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ class GridTests: IgniteTestSuite {
let output = element.render()

#expect(output == """
<div class="row">\
<div class="col g-3">\
<div class="row justify-content-center">\
<div class="col align-self-center g-3">\
<img src="/images/photos/shades.jpg" alt="A pair of sunglasses." class="img-fluid" />\
</div>\
<div class="col g-3">\
<div class="col align-self-center g-3">\
<img src="/images/photos/stack.jpg" alt="A door partly open." class="img-fluid" />\
</div>\
<div class="col g-3">\
<div class="col align-self-center g-3">\
<img src="/images/photos/wind.jpg" alt="A windy day." class="img-fluid" />\
</div>\
</div>
Expand All @@ -63,13 +63,13 @@ class GridTests: IgniteTestSuite {
let output = element.render()

#expect(output == """
<div class="row">\
<div class="col-md-4 g-3">\
<div class="row justify-content-center">\
<div class="col-md-4 align-self-center g-3">\
<img src="/images/photos/shades.jpg" alt="A pair of sunglasses." class="img-fluid" />\
</div>\
<div class="col-md-4 g-3"><img src="/images/photos/stack.jpg" alt="A door partly open." class="img-fluid" />\
<div class="col-md-4 align-self-center g-3"><img src="/images/photos/stack.jpg" alt="A door partly open." class="img-fluid" />\
</div>\
<div class="col-md-4 g-3">\
<div class="col-md-4 align-self-center g-3">\
<img src="/images/photos/wind.jpg" alt="A windy day." class="img-fluid" />\
</div>\
</div>
Expand Down Expand Up @@ -99,16 +99,16 @@ class GridTests: IgniteTestSuite {
let output = element.render()

#expect(output == """
<div class="row">\
<div class="col-md-4 g-3">\
<div class="row justify-content-center">\
<div class="col-md-4 align-self-center g-3">\
<img src="/images/photos/shades.jpg" alt="A pair of sunglasses." class="img-fluid" />\
</div>\
<div class="col-md-4 g-3">\
<div class="col-md-4 align-self-center g-3">\
<img src="/images/photos/stack.jpg" alt="A door partly open." class="img-fluid" />\
</div>\
<div class="col-md-4 g-3"><img src="/images/photos/rug.jpg" alt="A nice rug." class="img-fluid" />\
<div class="col-md-4 align-self-center g-3"><img src="/images/photos/rug.jpg" alt="A nice rug." class="img-fluid" />\
</div>\
<div class="col-md-4 g-3">\
<div class="col-md-4 align-self-center g-3">\
<img src="/images/photos/car.jpg" alt="The window of a car." class="img-fluid" />\
</div>\
</div>
Expand All @@ -135,17 +135,17 @@ class GridTests: IgniteTestSuite {
let output = element.render()

#expect(output == """
<div class="row row-cols-1 row-cols-md-2">\
<div class="col g-3">\
<div class="row justify-content-center row-cols-1 row-cols-md-2">\
<div class="col align-self-center g-3">\
<img src="/images/photos/shades.jpg" alt="A pair of sunglasses." class="img-fluid" />\
</div>\
<div class="col g-3">\
<div class="col align-self-center g-3">\
<img src="/images/photos/stack.jpg" alt="A door partly open." class="img-fluid" />\
</div>\
<div class="col g-3">\
<div class="col align-self-center g-3">\
<img src="/images/photos/rug.jpg" alt="A nice rug." class="img-fluid" />\
</div>\
<div class="col g-3"><img src="/images/photos/car.jpg" alt="The window of a car." class="img-fluid" />\
<div class="col align-self-center g-3"><img src="/images/photos/car.jpg" alt="The window of a car." class="img-fluid" />\
</div>\
</div>
""")
Expand Down