From 53a51f5d127b3adbb772964cbe8e27ab19d9675f Mon Sep 17 00:00:00 2001
From: Sascha Eggenberger <seggenberger@gitlab.com>
Date: Thu, 1 Feb 2024 17:05:19 +0000
Subject: [PATCH] Add GlSingleStat to haml

Adds the GlSingleStat component as a HAML component.

Changelog: changed
---
 .../pajamas/single_stat_component.html.haml   | 20 ++++++
 .../pajamas/single_stat_component.rb          | 56 ++++++++++++++++
 .../pajamas/single_stat_component_spec.rb     | 64 +++++++++++++++++++
 .../pajamas/single_stat_component_preview.rb  | 38 +++++++++++
 4 files changed, 178 insertions(+)
 create mode 100644 app/components/pajamas/single_stat_component.html.haml
 create mode 100644 app/components/pajamas/single_stat_component.rb
 create mode 100644 spec/components/pajamas/single_stat_component_spec.rb
 create mode 100644 spec/components/previews/pajamas/single_stat_component_preview.rb

diff --git a/app/components/pajamas/single_stat_component.html.haml b/app/components/pajamas/single_stat_component.html.haml
new file mode 100644
index 0000000000000..a5ee88fa476b9
--- /dev/null
+++ b/app/components/pajamas/single_stat_component.html.haml
@@ -0,0 +1,20 @@
+.gl-single-stat.gl-display-flex.gl-flex-direction-column.gl-p-2
+  .gl-display-flex.gl-align-items-center.gl-text-gray-700.gl-mb-2
+    - if title_icon?
+      = sprite_icon(@title_icon, css_class: 'gl-mr-2')
+    %span.gl-font-base.gl-font-weight-normal{ data: { testid: 'title-text' } }
+      = @title
+  .gl-single-stat-content.gl-display-flex.gl-align-items-baseline.gl-font-weight-bold.gl-text-gray-900
+    %span.gl-single-stat-number.gl-line-height-1{ class: unit_class, data: { testid: 'displayValue' } }
+      %span{ data: { testid: 'non-animated-value' } }
+        = @stat_value
+    - if unit?
+      %span.gl-font-sm.gl-mx-2.gl-transition-medium.gl-opacity-10{ data: { testid: 'unit' } }
+        = @unit
+    - if meta_icon? && !meta_text?
+      = sprite_icon(@meta_icon, css_class: @text_color)
+    - elsif meta_text?
+      = render Pajamas::BadgeComponent.new(@meta_text,
+        variant: @variant,
+        icon: @meta_icon,
+        data: { testid: 'meta-badge' })
diff --git a/app/components/pajamas/single_stat_component.rb b/app/components/pajamas/single_stat_component.rb
new file mode 100644
index 0000000000000..6c1a386eaaafe
--- /dev/null
+++ b/app/components/pajamas/single_stat_component.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+module Pajamas
+  class SingleStatComponent < Pajamas::Component
+    # @param [String] title
+    # @param [String] stat_value
+    # @param [String] unit
+    # @param [String] title_icon
+    # @param [String] meta_text
+    # @param [String] meta_icon
+    # @param [Symbol] variant
+    def initialize(
+      title: nil,
+      stat_value: nil,
+      unit: nil,
+      title_icon: nil,
+      meta_text: nil,
+      meta_icon: nil,
+      text_color: nil,
+      variant: :muted
+    )
+      @title = title
+      @stat_value = stat_value
+      @unit = unit
+      @title_icon = title_icon.to_s.presence
+      @meta_text = meta_text
+      @meta_icon = meta_icon
+      @text_color = text_color
+      @variant = filter_attribute(variant.to_sym, Pajamas::BadgeComponent::VARIANT_OPTIONS, default: :muted)
+    end
+
+    private
+
+    delegate :sprite_icon, to: :helpers
+
+    def unit_class
+      "gl-mr-2" unless unit?
+    end
+
+    def unit?
+      @unit
+    end
+
+    def title_icon?
+      @title_icon
+    end
+
+    def meta_icon?
+      @meta_icon
+    end
+
+    def meta_text?
+      @meta_text
+    end
+  end
+end
diff --git a/spec/components/pajamas/single_stat_component_spec.rb b/spec/components/pajamas/single_stat_component_spec.rb
new file mode 100644
index 0000000000000..620cc8dedca9f
--- /dev/null
+++ b/spec/components/pajamas/single_stat_component_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe Pajamas::SingleStatComponent, type: :component, feature_category: :shared do
+  let(:title) { "Single Stat" }
+  let(:stat_value) { "9,000" }
+  let(:title_icon) { nil }
+  let(:unit) { nil }
+  let(:meta_text) { nil }
+  let(:variant) { :success }
+
+  before do
+    render_inline(described_class.new(
+      title: title,
+      title_icon: title_icon,
+      stat_value: stat_value,
+      unit: unit,
+      meta_text: meta_text
+    ))
+  end
+
+  context "with default props" do
+    it 'shows title' do
+      expect(page).to have_css('[data-testid=title-text]', text: title)
+    end
+
+    it 'shows stat_value' do
+      expect(page).to have_css('[data-testid=non-animated-value]', text: stat_value)
+    end
+
+    it 'does not show unit' do
+      expect(page).not_to have_css('[data-testid=unit]')
+    end
+
+    it 'does not show meta badge' do
+      expect(page).not_to have_css('[data-testid=meta-badge]')
+    end
+  end
+
+  context "with title_icon" do
+    let(:title_icon) { :tanuki }
+
+    it 'shows icon' do
+      expect(page).to have_css('svg[data-testid=tanuki-icon]')
+    end
+  end
+
+  context 'with unit' do
+    let(:unit) { 'KB' }
+
+    it 'shows unit' do
+      expect(page).to have_css('[data-testid=unit]', text: unit)
+    end
+  end
+
+  context 'with meta_text' do
+    let(:meta_text) { "You're doing great!" }
+
+    it 'shows badge with text' do
+      expect(page).to have_css('[data-testid=meta-badge]', text: meta_text)
+    end
+  end
+end
diff --git a/spec/components/previews/pajamas/single_stat_component_preview.rb b/spec/components/previews/pajamas/single_stat_component_preview.rb
new file mode 100644
index 0000000000000..8519c96633f3a
--- /dev/null
+++ b/spec/components/previews/pajamas/single_stat_component_preview.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Pajamas
+  class SingleStatComponentPreview < ViewComponent::Preview
+    # SingleStat
+    # ---
+    #
+    # See its design reference [here](https://design.gitlab.com/data-visualization/single-stat).
+    #
+    # @param title text
+    # @param stat_value text
+    # @param unit text
+    # @param title_icon text
+    # @param meta_text text
+    # @param meta_icon text
+    # @param variant select {{ Pajamas::BadgeComponent::VARIANT_OPTIONS }}
+    # @param hide_units toggle
+    def default(
+      title: 'Single stat',
+      stat_value: '9,001',
+      unit: '',
+      title_icon: 'chart',
+      meta_text: '',
+      meta_icon: 'check-circle',
+      variant: :default
+    )
+      render Pajamas::SingleStatComponent.new(
+        title: title,
+        stat_value: stat_value,
+        unit: unit,
+        title_icon: title_icon,
+        meta_text: meta_text,
+        meta_icon: meta_icon,
+        variant: variant
+      )
+    end
+  end
+end
-- 
GitLab