From 969fca04b901e36e073eae6579c5ed0d2e6977f2 Mon Sep 17 00:00:00 2001 From: mhenrixon Date: Sat, 8 Nov 2025 08:17:17 +0100 Subject: [PATCH 1/2] Add Indicator component - Implements Indicator component with DaisyUI styling - Adds comprehensive test coverage - Includes responsive class comments for Tailwind --- lib/phlexy_ui/indicator.rb | 78 +++++++++++++++++++ spec/lib/phlexy_ui/indicator_spec.rb | 110 +++++++++++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 lib/phlexy_ui/indicator.rb create mode 100644 spec/lib/phlexy_ui/indicator_spec.rb diff --git a/lib/phlexy_ui/indicator.rb b/lib/phlexy_ui/indicator.rb new file mode 100644 index 0000000..f61cf40 --- /dev/null +++ b/lib/phlexy_ui/indicator.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +module PhlexyUI + # @component html class="indicator" + class Indicator < Base + def initialize(*, as: :div, **) + super(*, **) + @as = as + end + + def view_template(&) + generate_classes!( + # "indicator" + component_html_class: :indicator, + modifiers_map: modifiers, + base_modifiers:, + options: + ).then do |classes| + public_send(as, class: classes, **options, &) + end + end + + def item(**options, &) + generate_classes!( + # "indicator-item" + component_html_class: :"indicator-item", + options: + ).then do |classes| + span(class: classes, **options, &) + end + end + + register_modifiers( + # "sm:indicator-start" + # "@sm:indicator-start" + # "md:indicator-start" + # "@md:indicator-start" + # "lg:indicator-start" + # "@lg:indicator-start" + start: "indicator-start", + # "sm:indicator-center" + # "@sm:indicator-center" + # "md:indicator-center" + # "@md:indicator-center" + # "lg:indicator-center" + # "@lg:indicator-center" + center: "indicator-center", + # "sm:indicator-end" + # "@sm:indicator-end" + # "md:indicator-end" + # "@md:indicator-end" + # "lg:indicator-end" + # "@lg:indicator-end" + end: "indicator-end", + # "sm:indicator-top" + # "@sm:indicator-top" + # "md:indicator-top" + # "@md:indicator-top" + # "lg:indicator-top" + # "@lg:indicator-top" + top: "indicator-top", + # "sm:indicator-middle" + # "@sm:indicator-middle" + # "md:indicator-middle" + # "@md:indicator-middle" + # "lg:indicator-middle" + # "@lg:indicator-middle" + middle: "indicator-middle", + # "sm:indicator-bottom" + # "@sm:indicator-bottom" + # "md:indicator-bottom" + # "@md:indicator-bottom" + # "lg:indicator-bottom" + # "@lg:indicator-bottom" + bottom: "indicator-bottom" + ) + end +end diff --git a/spec/lib/phlexy_ui/indicator_spec.rb b/spec/lib/phlexy_ui/indicator_spec.rb new file mode 100644 index 0000000..22ac02a --- /dev/null +++ b/spec/lib/phlexy_ui/indicator_spec.rb @@ -0,0 +1,110 @@ +require "spec_helper" + +describe PhlexyUI::Indicator do + subject(:output) { render described_class.new } + + it "is expected to match the formatted HTML" do + expected_html = html <<~HTML +
+ HTML + + is_expected.to eq(expected_html) + end + + describe "with item method" do + subject(:output) do + render described_class.new do |i| + i.item { "Badge" } + end + end + + it "renders item" do + expected_html = html <<~HTML +
+ Badge +
+ HTML + + expect(output).to eq(expected_html) + end + end + + describe "conditions" do + { + start: "indicator-start", + center: "indicator-center", + end: "indicator-end", + top: "indicator-top", + middle: "indicator-middle", + bottom: "indicator-bottom" + }.each do |modifier, css| + context "when given :#{modifier} modifier" do + subject(:output) { render described_class.new(modifier) } + + it "renders it apart from the main class" do + expected_html = html <<~HTML +
+ HTML + + expect(output).to eq(expected_html) + end + end + end + + context "when given multiple conditions" do + subject(:output) { render described_class.new(:top, :end) } + + it "renders them separately" do + expected_html = html <<~HTML +
+ HTML + + expect(output).to eq(expected_html) + end + end + end + + describe "data" do + subject(:output) do + render described_class.new(data: {foo: "bar"}) + end + + it "renders it correctly" do + expected_html = html <<~HTML +
+ HTML + + expect(output).to eq(expected_html) + end + end + + describe "responsiveness" do + %i[sm md lg xl @sm @md @lg @xl].each do |viewport| + context "when given an :#{viewport} responsive option" do + subject(:output) do + render described_class.new(:top, responsive: {viewport => :bottom}) + end + + it "renders it separately with a responsive prefix" do + expected_html = html <<~HTML +
+ HTML + + expect(output).to eq(expected_html) + end + end + end + end + + describe "passing :as option" do + subject(:output) { render described_class.new(as: :span) } + + it "renders as the given tag" do + expected_html = html <<~HTML + + HTML + + expect(output).to eq(expected_html) + end + end +end From e73218abe7b0007c36465bfd580a2cfb0728524d Mon Sep 17 00:00:00 2001 From: David Alejandro <15317732+davidalejandroaguilar@users.noreply.github.com> Date: Wed, 12 Nov 2025 21:23:48 -0600 Subject: [PATCH 2/2] Add Indicator component --- lib/phlexy_ui/indicator.rb | 58 +------------ lib/phlexy_ui/indicator_item.rb | 69 ++++++++++++++++ spec/lib/phlexy_ui/indicator_spec.rb | 119 +++++++++++++++++++++++---- 3 files changed, 175 insertions(+), 71 deletions(-) create mode 100644 lib/phlexy_ui/indicator_item.rb diff --git a/lib/phlexy_ui/indicator.rb b/lib/phlexy_ui/indicator.rb index f61cf40..53c8b08 100644 --- a/lib/phlexy_ui/indicator.rb +++ b/lib/phlexy_ui/indicator.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true module PhlexyUI - # @component html class="indicator" class Indicator < Base def initialize(*, as: :div, **) super(*, **) @@ -12,67 +11,14 @@ def view_template(&) generate_classes!( # "indicator" component_html_class: :indicator, - modifiers_map: modifiers, - base_modifiers:, options: ).then do |classes| public_send(as, class: classes, **options, &) end end - def item(**options, &) - generate_classes!( - # "indicator-item" - component_html_class: :"indicator-item", - options: - ).then do |classes| - span(class: classes, **options, &) - end + def item(*base_modifiers, **, &) + render IndicatorItem.new(*base_modifiers, **, &) end - - register_modifiers( - # "sm:indicator-start" - # "@sm:indicator-start" - # "md:indicator-start" - # "@md:indicator-start" - # "lg:indicator-start" - # "@lg:indicator-start" - start: "indicator-start", - # "sm:indicator-center" - # "@sm:indicator-center" - # "md:indicator-center" - # "@md:indicator-center" - # "lg:indicator-center" - # "@lg:indicator-center" - center: "indicator-center", - # "sm:indicator-end" - # "@sm:indicator-end" - # "md:indicator-end" - # "@md:indicator-end" - # "lg:indicator-end" - # "@lg:indicator-end" - end: "indicator-end", - # "sm:indicator-top" - # "@sm:indicator-top" - # "md:indicator-top" - # "@md:indicator-top" - # "lg:indicator-top" - # "@lg:indicator-top" - top: "indicator-top", - # "sm:indicator-middle" - # "@sm:indicator-middle" - # "md:indicator-middle" - # "@md:indicator-middle" - # "lg:indicator-middle" - # "@lg:indicator-middle" - middle: "indicator-middle", - # "sm:indicator-bottom" - # "@sm:indicator-bottom" - # "md:indicator-bottom" - # "@md:indicator-bottom" - # "lg:indicator-bottom" - # "@lg:indicator-bottom" - bottom: "indicator-bottom" - ) end end diff --git a/lib/phlexy_ui/indicator_item.rb b/lib/phlexy_ui/indicator_item.rb new file mode 100644 index 0000000..c162965 --- /dev/null +++ b/lib/phlexy_ui/indicator_item.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module PhlexyUI + class IndicatorItem < Base + def initialize(*, as: :span, **) + super(*, **) + @as = as + end + + def view_template(&) + generate_classes!( + # "indicator-item" + component_html_class: :"indicator-item", + modifiers_map: modifiers, + base_modifiers:, + options: + ).then do |classes| + public_send(as, class: classes, **options, &) + end + end + + private + + register_modifiers( + # "sm:indicator-start" + # "@sm:indicator-start" + # "md:indicator-start" + # "@md:indicator-start" + # "lg:indicator-start" + # "@lg:indicator-start" + start: "indicator-start", + # "sm:indicator-center" + # "@sm:indicator-center" + # "md:indicator-center" + # "@md:indicator-center" + # "lg:indicator-center" + # "@lg:indicator-center" + center: "indicator-center", + # "sm:indicator-end" + # "@sm:indicator-end" + # "md:indicator-end" + # "@md:indicator-end" + # "lg:indicator-end" + # "@lg:indicator-end" + end: "indicator-end", + # "sm:indicator-top" + # "@sm:indicator-top" + # "md:indicator-top" + # "@md:indicator-top" + # "lg:indicator-top" + # "@lg:indicator-top" + top: "indicator-top", + # "sm:indicator-middle" + # "@sm:indicator-middle" + # "md:indicator-middle" + # "@md:indicator-middle" + # "lg:indicator-middle" + # "@lg:indicator-middle" + middle: "indicator-middle", + # "sm:indicator-bottom" + # "@sm:indicator-bottom" + # "md:indicator-bottom" + # "@md:indicator-bottom" + # "lg:indicator-bottom" + # "@lg:indicator-bottom" + bottom: "indicator-bottom" + ) + end +end diff --git a/spec/lib/phlexy_ui/indicator_spec.rb b/spec/lib/phlexy_ui/indicator_spec.rb index 22ac02a..d49caac 100644 --- a/spec/lib/phlexy_ui/indicator_spec.rb +++ b/spec/lib/phlexy_ui/indicator_spec.rb @@ -11,17 +11,19 @@ is_expected.to eq(expected_html) end - describe "with item method" do + describe "with item" do subject(:output) do render described_class.new do |i| - i.item { "Badge" } + i.item { "Badge 1" } + i.item { "Badge 2" } end end it "renders item" do expected_html = html <<~HTML
- Badge + Badge 1 + Badge 2
HTML @@ -38,12 +40,18 @@ middle: "indicator-middle", bottom: "indicator-bottom" }.each do |modifier, css| - context "when given :#{modifier} modifier" do - subject(:output) { render described_class.new(modifier) } + context "when given :#{modifier} modifier on an item" do + subject(:output) do + render described_class.new do |indicator| + indicator.item modifier + end + end it "renders it apart from the main class" do expected_html = html <<~HTML -
+
+ +
HTML expect(output).to eq(expected_html) @@ -51,12 +59,18 @@ end end - context "when given multiple conditions" do - subject(:output) { render described_class.new(:top, :end) } + context "when given multiple conditions on an item" do + subject(:output) do + render described_class.new do |indicator| + indicator.item :top, :end + end + end it "renders them separately" do expected_html = html <<~HTML -
+
+ +
HTML expect(output).to eq(expected_html) @@ -66,12 +80,16 @@ describe "data" do subject(:output) do - render described_class.new(data: {foo: "bar"}) + render described_class.new(data: {foo: "bar"}) do |indicator| + indicator.item data: {baz: "qux"} + end end it "renders it correctly" do expected_html = html <<~HTML -
+
+ +
HTML expect(output).to eq(expected_html) @@ -82,12 +100,18 @@ %i[sm md lg xl @sm @md @lg @xl].each do |viewport| context "when given an :#{viewport} responsive option" do subject(:output) do - render described_class.new(:top, responsive: {viewport => :bottom}) + render described_class.new do |indicator| + indicator.item responsive: {viewport => :bottom} + indicator.item responsive: {viewport => true} + end end it "renders it separately with a responsive prefix" do expected_html = html <<~HTML -
+
+ + +
HTML expect(output).to eq(expected_html) @@ -97,11 +121,76 @@ end describe "passing :as option" do - subject(:output) { render described_class.new(as: :span) } + subject(:output) { render described_class.new(as: :div) } it "renders as the given tag" do expected_html = html <<~HTML - +
+ HTML + + expect(output).to eq(expected_html) + end + end + + describe "rendering via Kit" do + subject(:output) do + Indicator do |indicator| + indicator.item :top + end + end + + it "renders it correctly" do + expected_html = html <<~HTML +
+ +
+ HTML + + expect(output).to eq(expected_html) + end + end + + describe "rendering a full indicator" do + let(:component) do + Class.new(Phlex::HTML) do + def view_template(&) + # Ignores :top modifier on the main component + render PhlexyUI::Indicator.new(:top, data: {foo: "bar"}) do |i| + i.item(:top, :start, class: "badge", data: {baz: "qux"}) { "↖︎" } + i.item(:top, :center, class: "badge") { "↑" } + i.item(:top, :end, class: "badge") { "↗︎" } + i.item(:middle, :start, class: "badge") { "←" } + i.item(:middle, :center, class: "badge") { "●" } + i.item(:middle, :end, class: "badge") { "→" } + i.item(:bottom, :start, class: "badge") { "↙︎" } + i.item(:bottom, :center, class: "badge") { "↓" } + i.item(:bottom, :end, class: "badge") { "↘︎" } + div(class: "bg-base-300 grid h-32 w-60 place-items-center") do + "Box" + end + end + end + end + end + + subject(:output) do + render component.new + end + + it "renders it correctly" do + expected_html = html <<~HTML +
+ ↖︎ + + ↗︎ + + + + ↙︎ + + ↘︎ +
Box
+
HTML expect(output).to eq(expected_html)