diff --git a/app/assets/stylesheets/koi/components/_index-table.scss b/app/assets/stylesheets/koi/components/_index-table.scss
index 981a0a9ab..4e278f43e 100644
--- a/app/assets/stylesheets/koi/components/_index-table.scss
+++ b/app/assets/stylesheets/koi/components/_index-table.scss
@@ -62,8 +62,11 @@ $row-height: 48px !default;
max-height: 3rem;
padding: 0;
}
+ }
- &.number {
+ td {
+ &.koi--tables-col-currency,
+ &.koi--tables-col-number {
text-align: right;
padding-right: 0.5rem;
}
@@ -71,6 +74,22 @@ $row-height: 48px !default;
th {
font-weight: bold;
+
+ &.koi--tables-col-xs {
+ width: 5rem;
+ }
+
+ &.koi--tables-col-s {
+ width: 8rem;
+ }
+
+ &.koi--tables-col-m {
+ width: 12rem;
+ }
+
+ &.koi--tables-col-l {
+ width: 20rem;
+ }
}
thead a.ascending:after,
diff --git a/app/components/koi/tables/body.rb b/app/components/koi/tables/body.rb
index a33092c24..5535f26d9 100644
--- a/app/components/koi/tables/body.rb
+++ b/app/components/koi/tables/body.rb
@@ -11,6 +11,7 @@ def rendered_value
end
# Formats the value as a date
+ #
# default format is :admin
class DateComponent < BodyCellComponent
def initialize(table, record, attribute, format: :admin, **options)
@@ -25,6 +26,7 @@ def rendered_value
end
# Formats the value as a datetime
+ #
# default format is :admin
class DatetimeComponent < BodyCellComponent
def initialize(table, record, attribute, format: :admin, **options)
@@ -39,19 +41,27 @@ def rendered_value
end
# Formats the value as a money value
- # The value is expected to be in cents
+ #
+ # The value is expected to be in cents.
# Adds a class to the cell to allow for custom styling
- class MoneyComponent < BodyCellComponent
+ class CurrencyComponent < BodyCellComponent
+ def initialize(table, record, attribute, options: {}, **html_attributes)
+ super(table, record, attribute, **html_attributes)
+
+ @options = options
+ end
+
def rendered_value
- value.present? ? number_to_currency(value / 100.0) : ""
+ value.present? ? number_to_currency(value / 100.0, @options) : ""
end
def default_html_attributes
- { class: "number" }
+ { class: "koi--tables-col-currency" }
end
end
# Formats the value as a number
+ #
# Adds a class to the cell to allow for custom styling
class NumberComponent < BodyCellComponent
def rendered_value
@@ -59,11 +69,12 @@ def rendered_value
end
def default_html_attributes
- { class: "number" }
+ { class: "koi--tables-col-number" }
end
end
# Displays the plain text for rich text content
+ #
# Adds a title attribute to allow for hover over display of the full content
class RichTextComponent < BodyCellComponent
def default_html_attributes
@@ -102,6 +113,7 @@ def url
end
# Shows a thumbnail image
+ #
# The value is expected to be an ActiveStorage attachment with a default variant named :thumb
class ImageComponent < BodyCellComponent
def initialize(table, record, attribute, variant: :thumb, **options)
diff --git a/app/components/koi/tables/body_row_component.rb b/app/components/koi/tables/body_row_component.rb
index ea2e7c1a6..3edcf8169 100644
--- a/app/components/koi/tables/body_row_component.rb
+++ b/app/components/koi/tables/body_row_component.rb
@@ -4,44 +4,152 @@ module Koi
module Tables
# Custom body row component, in order to override the default body cell component
class BodyRowComponent < Katalyst::Tables::BodyRowComponent
- def boolean(attribute, **options, &block)
- with_column(Body::BooleanComponent.new(@table, @record, attribute, **options), &block)
+ # Generates a column from boolean values rendered as "Yes" or "No".
+ #
+ # @param method [Symbol] the method to call on the record
+ # @param attributes [Hash] HTML attributes to be added to the cell
+ # @param block [Proc] optional block to alter the cell content
+ # @return [void]
+ #
+ # @example Render a boolean column indicating whether the record is active
+ # <% row.boolean :active %> # =>
Yes |
+ def boolean(method, **attributes, &block)
+ with_column(Body::BooleanComponent.new(@table, @record, method, **attributes), &block)
end
- def date(attribute, format: :admin, **options, &block)
- with_column(Body::DateComponent.new(@table, @record, attribute, format:, **options), &block)
+ # Generates a column from date values rendered using I18n.l.
+ # The default format is :admin, but it can be overridden.
+ #
+ # @param method [Symbol] the method to call on the record
+ # @param format [Symbol] the I18n date format to use when rendering
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
+ # @param block [Proc] optional block to alter the cell content
+ # @return [void]
+ #
+ # @example Render a date column describing when the record was created
+ # <% row.date :created_at %> # => 29 Feb 2024 |
+ def date(method, format: :admin, **attributes, &block)
+ with_column(Body::DateComponent.new(@table, @record, method, format:, **attributes), &block)
end
- def datetime(attribute, format: :admin, **options, &block)
- with_column(Body::DatetimeComponent.new(@table, @record, attribute, format:, **options), &block)
+ # Generates a column from datetime values rendered using I18n.l.
+ # The default format is :admin, but it can be overridden.
+ #
+ # @param method [Symbol] the method to call on the record
+ # @param format [Symbol] the I18n datetime format to use when rendering
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
+ # @param block [Proc] optional block to alter the cell content
+ # @return [void]
+ #
+ # @example Render a datetime column describing when the record was created
+ # <% row.datetime :created_at %> # => 29 Feb 2024, 5:00pm |
+ def datetime(method, format: :admin, **attributes, &block)
+ with_column(Body::DatetimeComponent.new(@table, @record, method, format:, **attributes), &block)
end
- def number(attribute, **options, &block)
- with_column(Body::NumberComponent.new(@table, @record, attribute, **options), &block)
+ # Generates a column from numeric values formatted appropriately.
+ #
+ # @param method [Symbol] the method to call on the record
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
+ # @param block [Proc] optional block to alter the cell content
+ # @return [void]
+ #
+ # @example Render the number of comments on a post
+ # <% row.number :comment_count %> # => 0 |
+ def number(method, **attributes, &block)
+ with_column(Body::NumberComponent.new(@table, @record, method, **attributes), &block)
end
- def money(attribute, **options, &block)
- with_column(Body::MoneyComponent.new(@table, @record, attribute, **options), &block)
+ # Generates a column from numeric values rendered using `number_to_currency`.
+ #
+ # @param method [Symbol] the method to call on the record
+ # @param options [Hash] options to be passed to `number_to_currency`
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
+ # @param block [Proc] optional block to alter the cell content
+ # @return [void]
+ #
+ # @example Render a currency column for the price of a product
+ # <% row.currency :price %> # => $3.50 |
+ def currency(method, options: {}, **attributes, &block)
+ with_column(Body::CurrencyComponent.new(@table, @record, method, options:, **attributes), &block)
end
- def rich_text(attribute, **options, &block)
- with_column(Body::RichTextComponent.new(@table, @record, attribute, **options), &block)
+ # Generates a column containing HTML markup.
+ #
+ # @param method [Symbol] the method to call on the record
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
+ # @param block [Proc] optional block to alter the cell content
+ # @return [void]
+ #
+ # @note This method assumes that the method returns HTML-safe content.
+ # If the content is not HTML-safe, it will be escaped.
+ #
+ # @example Render a description column containing HTML markup
+ # <% row.rich_text :description %> # => Emphasis |
+ def rich_text(method, **attributes, &block)
+ with_column(Body::RichTextComponent.new(@table, @record, method, **attributes), &block)
end
- def link(attribute, url: [:admin, @record], link: {}, **attributes, &block)
- with_column(Body::LinkComponent.new(@table, @record, attribute, url:, link:, **attributes), &block)
+ # Generates a column that links to the record's show page (by default).
+ #
+ # @param method [Symbol] the method to call on the record
+ # @param link [Hash] options to be passed to the link_to helper
+ # @option opts [Hash, Array, String, Symbol] :url ([:admin, object]) options for url_for,
+ # or a symbol to be passed to the route helper
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
+ # @param block [Proc] optional block to alter the cell content
+ # @return [void]
+ #
+ # @example Render a column containing the record's title, linked to its show page
+ # <% row.link :title %> # => About us |
+ # @example Render a column containing the record's title, linked to its edit page
+ # <% row.link :title, url: :edit_admin_post_path do |cell| %>
+ # Edit <%= cell %>
+ # <% end %>
+ # # => Edit About us |
+ def link(method, url: [:admin, @record], link: {}, **attributes, &block)
+ with_column(Body::LinkComponent.new(@table, @record, method, url:, link:, **attributes), &block)
end
- def text(attribute, **options, &block)
- with_column(BodyCellComponent.new(@table, @record, attribute, **options), &block)
+ # Generates a column that renders the contents as text.
+ #
+ # @param method [Symbol] the method to call on the record
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
+ # @param block [Proc] optional block to alter the cell content
+ # @return [void]
+ #
+ # @example Render a column containing the record's title
+ # <% row.text :title %> # => About us |
+ def text(method, **attributes, &block)
+ with_column(BodyCellComponent.new(@table, @record, method, **attributes), &block)
end
- def image(attribute, variant: :thumb, **options, &block)
- with_column(Body::ImageComponent.new(@table, @record, attribute, variant:, **options), &block)
+ # Generates a column that renders an ActiveStorage attachment as an image.
+ # Assumes that a variant called `:thumb` is defined for the attachment.
+ #
+ # @param method [Symbol] the method to call on the record
+ # @param variant [Symbol] the variant to use when rendering the image (default :thumb)
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
+ # @param block [Proc] optional block to alter the cell content
+ # @return [void]
+ #
+ # @example Render a column containing a thumbnail of the record's background image
+ # <% row.image :background %> # =>  |
+ def image(method, variant: :thumb, **attributes, &block)
+ with_column(Body::ImageComponent.new(@table, @record, method, variant:, **attributes), &block)
end
- def attachment(attribute, **options, &block)
- with_column(Body::AttachmentComponent.new(@table, @record, attribute, **options), &block)
+ # Generates a column that renders an ActiveStorage attachment as a downloadable link.
+ #
+ # @param method [Symbol] the method to call on the record
+ # @param attributes [Hash] HTML attributes to be added to the cell tag
+ # @param block [Proc] optional block to alter the cell content
+ # @return [void]
+ #
+ # @example Render a column containing a download link to the record's background image
+ # <% row.attachment :background %> # => background.png |
+ def attachment(method, **attributes, &block)
+ with_column(Body::AttachmentComponent.new(@table, @record, method, **attributes), &block)
end
end
end
diff --git a/app/components/koi/tables/header.rb b/app/components/koi/tables/header.rb
index 2d70be5e1..c372009e8 100644
--- a/app/components/koi/tables/header.rb
+++ b/app/components/koi/tables/header.rb
@@ -4,8 +4,94 @@ module Koi
module Tables
module Header
class NumberComponent < HeaderCellComponent
+ using Katalyst::HtmlAttributes::HasHtmlAttributes
+
+ def initialize(table, attribute, label: nil, link: {}, width: :xs, **html_attributes)
+ super(table, attribute, label:, link:, width:, **html_attributes)
+ end
+
+ def default_html_attributes
+ super.merge_html(class: "koi--tables-col-number")
+ end
+ end
+
+ class CurrencyComponent < HeaderCellComponent
+ using Katalyst::HtmlAttributes::HasHtmlAttributes
+
+ def initialize(table, attribute, label: nil, link: {}, width: :s, **html_attributes)
+ super(table, attribute, label:, link:, width:, **html_attributes)
+ end
+
+ def default_html_attributes
+ super.merge_html(class: "koi--tables-col-currency")
+ end
+ end
+
+ class BooleanComponent < HeaderCellComponent
+ using Katalyst::HtmlAttributes::HasHtmlAttributes
+
+ def initialize(table, attribute, label: nil, link: {}, width: :xs, **html_attributes)
+ super(table, attribute, label:, link:, width:, **html_attributes)
+ end
+
+ def default_html_attributes
+ super.merge_html(class: "koi--tables-col-boolean")
+ end
+ end
+
+ class DateComponent < HeaderCellComponent
+ using Katalyst::HtmlAttributes::HasHtmlAttributes
+
+ def initialize(table, attribute, label: nil, link: {}, width: :s, **html_attributes)
+ super(table, attribute, label:, link:, width:, **html_attributes)
+ end
+
+ def default_html_attributes
+ super.merge_html(class: "koi--tables-col-date")
+ end
+ end
+
+ class DateTimeComponent < HeaderCellComponent
+ using Katalyst::HtmlAttributes::HasHtmlAttributes
+
+ def initialize(table, attribute, label: nil, link: {}, width: :m, **html_attributes)
+ super(table, attribute, label:, link:, width:, **html_attributes)
+ end
+
+ def default_html_attributes
+ super.merge_html(class: "koi--tables-col-datetime")
+ end
+ end
+
+ class LinkComponent < HeaderCellComponent
+ using Katalyst::HtmlAttributes::HasHtmlAttributes
+
+ def default_html_attributes
+ super.merge_html(class: "koi--tables-col-link")
+ end
+ end
+
+ class TextComponent < HeaderCellComponent
+ using Katalyst::HtmlAttributes::HasHtmlAttributes
+
+ def default_html_attributes
+ super.merge_html(class: "koi--tables-col-text")
+ end
+ end
+
+ class ImageComponent < HeaderCellComponent
+ using Katalyst::HtmlAttributes::HasHtmlAttributes
+
+ def default_html_attributes
+ super.merge_html(class: "koi--tables-col-image")
+ end
+ end
+
+ class AttachmentComponent < HeaderCellComponent
+ using Katalyst::HtmlAttributes::HasHtmlAttributes
+
def default_html_attributes
- { class: "number" }
+ super.merge_html(class: "koi--tables-col-attachment")
end
end
end
diff --git a/app/components/koi/tables/header_cell_component.rb b/app/components/koi/tables/header_cell_component.rb
index 9240328f8..dc328334c 100644
--- a/app/components/koi/tables/header_cell_component.rb
+++ b/app/components/koi/tables/header_cell_component.rb
@@ -3,6 +3,36 @@
module Koi
module Tables
class HeaderCellComponent < Katalyst::Tables::HeaderCellComponent
+ using Katalyst::HtmlAttributes::HasHtmlAttributes
+
+ attr_reader :width
+
+ def initialize(table, attribute, label: nil, link: {}, width: nil, **html_attributes)
+ @width = width
+
+ super(table, attribute, label:, link:, **html_attributes)
+ end
+
+ def default_html_attributes
+ super.merge_html(class: width_class)
+ end
+
+ private
+
+ def width_class
+ case width
+ when :xs
+ "koi--tables-col-xs"
+ when :s
+ "koi--tables-col-s"
+ when :m
+ "koi--tables-col-m"
+ when :l
+ "koi--tables-col-l"
+ else
+ ""
+ end
+ end
end
end
end
diff --git a/app/components/koi/tables/header_row_component.rb b/app/components/koi/tables/header_row_component.rb
index 60f687524..4541499c9 100644
--- a/app/components/koi/tables/header_row_component.rb
+++ b/app/components/koi/tables/header_row_component.rb
@@ -5,50 +5,230 @@ module Tables
# Custom header row component, in order to override the default header cell component
# for number columns, we add a class to the header cell to allow for custom styling
class HeaderRowComponent < Katalyst::Tables::HeaderRowComponent
- def boolean(attribute, **attributes, &block)
- header_cell(attribute, **attributes, &block)
+ # Renders a boolean column header
+ # @param method [Symbol] the method to call on the record to get the value
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
+ # @option opts [String] :label (nil) The label options to display in the header
+ # @option opts [Hash] :link ({}) The link options for the sorting link
+ # @option opts [String] :width (:xs) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
+ #
+ # @example Render a boolean column header
+ # <% row.boolean :active %> # => Active |
+ #
+ # @example Render a boolean column header with a custom label
+ # <% row.boolean :active, label: "Published" %> # => Published |
+ #
+ # @example Render a boolean column header with medium width
+ # <% row.boolean :active, width: :m %>
+ # # => Active |
+ #
+ # @see Koi::Tables::BodyRowComponent#boolean
+ def boolean(method, **attributes, &block)
+ header_cell(method, component: Header::BooleanComponent, **attributes, &block)
end
- def date(attribute, **attributes, &block)
- header_cell(attribute, **attributes, &block)
+ # Renders a date column header
+ # @param method [Symbol] the method to call on the record to get the value
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
+ # @option opts [String] :label (nil) The label options to display in the header
+ # @option opts [Hash] :link ({}) The link options for the sorting link
+ # @option opts [String] :width (:s) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
+ #
+ # @example Render a date column header
+ # <% row.date :published_on %> # => Published on |
+ #
+ # @example Render a date column header with a custom label
+ # <% row.date :published_on, label: "Date" %> # => Date |
+ #
+ # @example Render a date column header with small width
+ # <% row.date :published_on, width: :s %>
+ # # => Published on |
+ #
+ # @see Koi::Tables::BodyRowComponent#date
+ def date(method, **attributes, &block)
+ header_cell(method, component: Header::DateComponent, **attributes, &block)
end
- def datetime(attribute, **attributes, &block)
- header_cell(attribute, **attributes, &block)
+ # Renders a datetime column header
+ # @param method [Symbol] the method to call on the record to get the value
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
+ # @option opts [String] :label (nil) The label options to display in the header
+ # @option opts [Hash] :link ({}) The link options for the sorting link
+ # @option opts [String] :width (:m) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
+ #
+ # @example Render a datetime column header
+ # <% row.datetime :created_at %> # => Created at |
+ #
+ # @example Render a datetime column header with a custom label
+ # <% row.datetime :created_at, label: "Published at" %> # => Published at |
+ #
+ # @example Render a datetime column header with small width
+ # <% row.datetime :created_at, width: :s %>
+ # # => Created at |
+ #
+ # @see Koi::Tables::BodyRowComponent#datetime
+ def datetime(method, **attributes, &block)
+ header_cell(method, component: Header::DateTimeComponent, **attributes, &block)
end
- def number(attribute, **attributes, &block)
- header_cell(attribute, **attributes, component: Header::NumberComponent, &block)
+ # Renders a number column header
+ # @param method [Symbol] the method to call on the record to get the value
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
+ # @option opts [String] :label (nil) The label options to display in the header
+ # @option opts [Hash] :link ({}) The link options for the sorting link
+ # @option opts [String] :width (:xs) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
+ #
+ # @example Render a number column header
+ # <% row.number :comment_count %> # => Comments |
+ #
+ # @example Render a number column header with a custom label
+ # <% row.number :comment_count, label: "Comments" %> # => Comments |
+ #
+ # @example Render a number column header with medium width
+ # <% row.number :comment_count, width: :m %>
+ # # => Comment Count |
+ #
+ # @see Koi::Tables::BodyRowComponent#number
+ def number(method, **attributes, &block)
+ header_cell(method, component: Header::NumberComponent, **attributes, &block)
end
- def money(attribute, **attributes, &block)
- header_cell(attribute, **attributes, component: Header::NumberComponent, &block)
+ # Renders a currency column header
+ # @param method [Symbol] the method to call on the record to get the value
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
+ # @option opts [String] :label (nil) The label options to display in the header
+ # @option opts [Hash] :link ({}) The link options for the sorting link
+ # @option opts [String] :width (:s) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
+ #
+ # @example Render a currency column header
+ # <% row.currency :price %> # => Price |
+ #
+ # @example Render a currency column header with a custom label
+ # <% row.currency :price, label: "Amount($)" %> # => Amount($) |
+ #
+ # @example Render a currency column header with medium width
+ # <% row.currency :price, width: :m %>
+ # # => Price |
+ #
+ # @see Koi::Tables::BodyRowComponent#currency
+ def currency(method, **attributes, &block)
+ header_cell(method, component: Header::CurrencyComponent, **attributes, &block)
end
- def rich_text(attribute, **attributes, &block)
- header_cell(attribute, **attributes, &block)
+ # Renders a rich text column header
+ # @param method [Symbol] the method to call on the record to get the value
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
+ # @option opts [String] :label (nil) The label options to display in the header
+ # @option opts [Hash] :link ({}) The link options for the sorting link
+ # @option opts [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
+ #
+ # @example Render a rich text column header
+ # <% row.rich_text :content %> # => Content |
+ #
+ # @example Render a rich text column header with a custom label
+ # <% row.rich_text :content, label: "Post content" %> # => Post content |
+ #
+ # @example Render a rich text column header with large width
+ # <% row.rich_text :content, width: :l %>
+ # # => Content |
+ #
+ # @see Koi::Tables::BodyRowComponent#rich_text
+ def rich_text(method, **attributes, &block)
+ header_cell(method, component: Header::TextComponent, **attributes, &block)
end
- def link(attribute, **attributes, &block)
- header_cell(attribute, **attributes, &block)
+ # Renders a link column header
+ # @param method [Symbol] the method to call on the record to get the value
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
+ # @option opts [String] :label (nil) The label options to display in the header
+ # @option opts [Hash] :link ({}) The link options for the sorting link
+ # @option opts [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
+ #
+ # @example Render a link column header
+ # <% row.link :link %> # => Link |
+ #
+ # @example Render a link column header with a custom label
+ # <% row.link :link, label: "Post" %> # => Post |
+ #
+ # @example Render a link column header with small width
+ # <% row.link :content, width: :s %>
+ # # => Content |
+ #
+ # @see Koi::Tables::BodyRowComponent#link
+ def link(method, **attributes, &block)
+ header_cell(method, component: Header::LinkComponent, **attributes, &block)
end
- def attachment(attribute, **attributes, &block)
- header_cell(attribute, type: :link, **attributes, &block)
+ # Renders a text column header
+ # @param method [Symbol] the method to call on the record to get the value
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
+ # @option opts [String] :label (nil) The label options to display in the header
+ # @option opts [Hash] :link ({}) The link options for the sorting link
+ # @option opts [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
+ #
+ # @example Render a text column header
+ # <% row.text :content %> # => Content |
+ #
+ # @example Render a text column header with a custom label
+ # <% row.text :content, label: "Description" %> # => Description |
+ #
+ # @example Render a text column header with large width
+ # <% row.text :content, width: :l %>
+ # # => Content |
+ #
+ # @see Koi::Tables::BodyRowComponent#text
+ def text(method, **attributes, &block)
+ header_cell(method, component: Header::TextComponent, **attributes, &block)
end
- def text(attribute, **attributes, &block)
- header_cell(attribute, **attributes, &block)
+ # Renders a image column header
+ # @param method [Symbol] the method to call on the record to get the value
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
+ # @option opts [String] :label (nil) The label options to display in the header
+ # @option opts [Hash] :link ({}) The link options for the sorting link
+ # @option opts [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
+ #
+ # @example Render a image column header
+ # <% row.image :image %> # => Image |
+ #
+ # @example Render a image column header with a custom label
+ # <% row.image :image, label: "Preview" %> # => Preview |
+ #
+ # @example Render a image column header with small width
+ # <% row.image :image, width: :s %>
+ # # => Content |
+ #
+ # @see Koi::Tables::BodyRowComponent#image
+ def image(method, **attributes, &block)
+ header_cell(method, component: Header::ImageComponent, **attributes, &block)
end
- def image(attribute, **attributes, &block)
- header_cell(attribute, **attributes, &block)
+ # Renders a attachment column header
+ # @param method [Symbol] the method to call on the record to get the value
+ # @param attributes [Hash] additional arguments are applied as html attributes to the th element
+ # @option opts [String] :label (nil) The label options to display in the header
+ # @option opts [Hash] :link ({}) The link options for the sorting link
+ # @option opts [String] :width (nil) The width of the column, can be +:xs+, +:s+, +:m+, +:l+ or nil
+ #
+ # @example Render a attachment column header
+ # <% row.attachment :attachment %> # => Attachment |
+ #
+ # @example Render a attachment column header with a custom label
+ # <% row.attachment :attachment, label: "Document" %> # => Document |
+ #
+ # @example Render a attachment column header with small width
+ # <% row.attachment :attachment, width: :s %>
+ # # => Attachment |
+ #
+ # @see Koi::Tables::BodyRowComponent#attachment
+ def attachment(method, **attributes, &block)
+ header_cell(method, component: Header::AttachmentComponent, **attributes, &block)
end
private
- def header_cell(attribute, component: HeaderCellComponent, **attributes, &block)
- with_column(component.new(@table, attribute, link: @link_attributes, **attributes), &block)
+ def header_cell(method, component: HeaderCellComponent, **attributes, &block)
+ with_column(component.new(@table, method, link: @link_attributes, **attributes), &block)
end
end
end
diff --git a/spec/components/koi/tables/body_spec.rb b/spec/components/koi/tables/body_spec.rb
index cbf5473a0..32533e55f 100644
--- a/spec/components/koi/tables/body_spec.rb
+++ b/spec/components/koi/tables/body_spec.rb
@@ -121,7 +121,18 @@
component = described_class.new(table, record, :ordinal)
rendered = render_inline(component)
expect(rendered).to match_html(<<~HTML)
- #{record.ordinal} |
+ #{record.ordinal} |
+ HTML
+ end
+ end
+
+ describe Koi::Tables::Body::CurrencyComponent do
+ it "renders column" do
+ record = create(:banner)
+ component = described_class.new(table, record, :ordinal)
+ rendered = render_inline(component)
+ expect(rendered).to match_html(<<~HTML)
+ $#{record.ordinal / 100.0} |
HTML
end
end
diff --git a/spec/components/koi/tables/header_spec.rb b/spec/components/koi/tables/header_spec.rb
new file mode 100644
index 000000000..fbcf1fc80
--- /dev/null
+++ b/spec/components/koi/tables/header_spec.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require "rails_helper"
+
+describe Koi::Tables::Header do
+ let(:table) { Koi::Tables::TableComponent.new(collection:, id: "table") }
+ let(:collection) { Post.all }
+
+ describe Koi::Tables::Header::BooleanComponent do
+ it "renders column header" do
+ component = described_class.new(table, :active)
+ rendered = render_inline(component)
+ expect(rendered).to match_html(<<~HTML)
+ Active |
+ HTML
+ end
+
+ context "when width is specified" do
+ it "renders column header" do
+ component = described_class.new(table, :active, width: :m)
+ rendered = render_inline(component)
+ expect(rendered).to match_html(<<~HTML)
+ Active |
+ HTML
+ end
+ end
+
+ context "when width is set to nil" do
+ it "renders column header" do
+ component = described_class.new(table, :active, width: nil)
+ rendered = render_inline(component)
+ expect(rendered).to match_html(<<~HTML)
+ Active |
+ HTML
+ end
+ end
+
+ context "when additional css class is specified" do
+ it "renders column header" do
+ component = described_class.new(table, :active, class: "custom-class")
+ rendered = render_inline(component)
+ expect(rendered).to match_html(<<~HTML)
+ Active |
+ HTML
+ end
+ end
+ end
+
+ describe Koi::Tables::Header::NumberComponent do
+ let(:collection) { Banner.all }
+
+ it "renders column header" do
+ component = described_class.new(table, :ordinal)
+ rendered = render_inline(component)
+ expect(rendered).to match_html(<<~HTML)
+ Ordinal |
+ HTML
+ end
+
+ context "with sorting" do
+ let(:collection) { Katalyst::Tables::Collection::Base.new(sorting: "ordinal desc").apply(Banner.all) }
+
+ it "renders column header" do
+ component = described_class.new(table, :ordinal)
+ rendered = render_inline(component)
+ expect(rendered).to match_html(<<~HTML)
+
+ Ordinal
+ |
+ HTML
+ end
+ end
+
+ context "with custom class and sorting" do
+ let(:collection) { Katalyst::Tables::Collection::Base.new(sorting: "ordinal desc").apply(Banner.all) }
+
+ it "renders column header" do
+ component = described_class.new(table, :ordinal, class: "custom-class")
+ rendered = render_inline(component)
+ expect(rendered).to match_html(<<~HTML)
+
+ Ordinal
+ |
+ HTML
+ end
+ end
+ end
+end
diff --git a/spec/components/koi/tables/table_component_spec.rb b/spec/components/koi/tables/table_component_spec.rb
index 11f30a6b8..5af82587e 100644
--- a/spec/components/koi/tables/table_component_spec.rb
+++ b/spec/components/koi/tables/table_component_spec.rb
@@ -23,26 +23,24 @@
end
it "renders column" do
- expect(table).to match_html(<<~HTML,
+ expect(table).to match_html(<<~HTML)
Name |
#{collection.items.first&.name} |
HTML
- )
end
context "with boolean" do
let(:content) { Proc.new { |row| row.boolean :active } }
it "renders boolean column" do
- expect(table).to match_html(<<~HTML,
+ expect(table).to match_html(<<~HTML)
HTML
- )
end
context "with content" do
@@ -55,13 +53,12 @@
end
it "renders boolean column with custom content" do
- expect(table).to match_html(<<~HTML,
+ expect(table).to match_html(<<~HTML)
HTML
- )
end
end
end
@@ -71,13 +68,12 @@
let(:content) { Proc.new { |row| row.date :published_on } }
it "renders date column" do
- expect(table).to match_html(<<~HTML,
+ expect(table).to match_html(<<~HTML)
- Published on |
+ Published on |
#{value} |
HTML
- )
end
end
@@ -86,13 +82,12 @@
let(:content) { Proc.new { |row| row.datetime :created_at } }
it "renders datetime column" do
- expect(table).to match_html(<<~HTML,
+ expect(table).to match_html(<<~HTML)
- Created at |
+ Created at |
#{value} |
HTML
- )
end
end
@@ -101,13 +96,12 @@
let(:content) { Proc.new { |row| row.number :ordinal } }
it "renders number column" do
- expect(table).to match_html(<<~HTML,
+ expect(table).to match_html(<<~HTML)
- Ordinal |
- #{collection.items.first&.ordinal} |
+ Ordinal |
+ #{collection.items.first&.ordinal} |
HTML
- )
end
end
@@ -115,9 +109,9 @@
let(:content) { Proc.new { |row| row.rich_text :content } }
it "renders rich text column" do
- expect(table).to match_html(<<~HTML,
+ expect(table).to match_html(<<~HTML)
- Content |
+ Content |
#{collection.items.first&.content}
@@ -125,7 +119,6 @@
|
HTML
- )
end
end
@@ -133,15 +126,14 @@
let(:content) { Proc.new { |row| row.link :name } }
it "renders link column" do
- expect(table).to match_html(<<~HTML,
+ expect(table).to match_html(<<~HTML)
HTML
- )
end
end
@@ -149,13 +141,12 @@
let(:content) { Proc.new { |row| row.text :title } }
it "renders text column" do
- expect(table).to match_html(<<~HTML,
+ expect(table).to match_html(<<~HTML)
- Title |
+ Title |
#{collection.items.first&.title} |
HTML
- )
end
end
end