Module: IconHelper

Constant Summary collapse

DEFAULT_FAMILY =
'sharp_regular'
CUSTOM_SVG_DIR =
Rails.root.join('app/assets/images/svgs/custom')
CUSTOM_ICON_MAP =
begin
  if Dir.exist?(CUSTOM_SVG_DIR)
    Dir.glob(File.join(CUSTOM_SVG_DIR, '*.svg'))
       .map { |file| File.basename(file, '.svg') }
       .sort
       .freeze
  else
    [].freeze
  end
end

Instance Method Summary collapse

Instance Method Details

#account_nav_icon(**opts) ⇒ Object

Navbar account icon. When the session is a masquerade (employee "Login as
this user" flow), renders a warning-coloured circular badge with an
inverted user-secret glyph, so the employee sees at a glance that they are
not in their real account. Falls through to the regular circle-user icon
otherwise.

Sized to occupy the same 1em footprint as circle-user via
.masquerade-account-icon in
client/stylesheets/www/02-objects/navbar.scss. fa-stack was avoided here
because its 2em default footprint would visibly inflate the navbar slot.



77
78
79
80
81
82
83
# File 'app/helpers/icon_helper.rb', line 77

def (**opts)
  if respond_to?(:account_impersonated?) && 
    (:span, **masquerade_icon_wrapper_opts(opts)) { fa_icon('user-secret', family: 'fas') }
  else
    fa_icon('circle-user', **opts.reverse_merge(family: 'far'))
  end
end

#fa_icon(icon = nil, options = {}) ⇒ Object

Usage: fa_icon('trash', family: :sharp_regular, class: 'me-1')



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'app/helpers/icon_helper.rb', line 37

def fa_icon(icon = nil, options = {})
  icon ||= 'question'
  opts = options.dup
  text_value = opts.delete(:text)
  text = text_value.is_a?(String) ? text_value.html_safe : text_value

  requested_family = (opts.delete(:family) || DEFAULT_FAMILY).to_s

  # Kit/custom icons: inline the local SVG if available
  if requested_family.in?(%w[custom kit fa-kit])
    icon_tag = inline_custom_svg(icon.to_s.tr('_', '-'), opts)
    return append_text(icon_tag, text)
  end

  family_classes = case requested_family
                   when 'fab', 'brands', 'fa-brands'
                     ['fa-brands']
                   when 'fas', 'solid', 'fa-solid', 'sharp-solid', 'sharp_solid', 'fa-sharp fa-solid'
                     %w[fa-sharp fa-solid]
                   else
                     %w[fa-sharp fa-regular]
                   end

  icon_class = "fa-#{icon.to_s.gsub(/_/m, '-')}"
  css_classes = [family_classes, icon_class, opts.delete(:class)].flatten.compact.join(' ')

  icon_tag = ActionController::Base.helpers.tag.i(nil, **opts, class: css_classes)
  append_text(icon_tag, text)
end

#star_rating_html(rating, icon_class: nil, rounding: :nearest) ⇒ Object

Discrete Font Awesome stars (full / half / empty) for ratings 0..5.

Parameters:

  • rounding (Symbol) (defaults to: :nearest)

    :nearest (half-star) or :floor



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'app/helpers/icon_helper.rb', line 19

def star_rating_html(rating, icon_class: nil, rounding: :nearest)
  clamped = rating.to_f.clamp(0.0, 5.0)
  rounded = case rounding
            when :floor then ((clamped * 2).floor / 2.0)
            else ((clamped * 2).round / 2.0)
            end
  full  = rounded.floor
  half  = (rounded - full) >= 0.5
  empty = 5 - full - (half ? 1 : 0)

  nodes = []
  full.times  { nodes << fa_icon('star', family: :sharp_solid, class: icon_class) }
  nodes << fa_icon('star-half-stroke', family: :sharp_solid, class: icon_class) if half
  empty.times { nodes << fa_icon('star', family: :sharp_regular, class: icon_class) }
  safe_join(nodes)
end