Module: WwwHelper

Defined in:
app/helpers/www_helper.rb

Instance Method Summary collapse

Instance Method Details

#build_canonical_paths(url, locales: %i[en-US en-CA],, parameters: nil, request_url: nil) ⇒ Object

This method generates a set of alternate language tag and canonical tag
see https://www.semrush.com/blog/the-most-common-hreflang-mistakes-infographic/
https://www.rebelytics.com/hreflang-canonical/
https://www.portent.com/blog/seo/implement-hreflang-canonical-tags-correctly.htm
First argument is url, the target url to build canonical paths for
Somethings this url might not be the current page, that's why request_url can be passed to do this check
You only want the alternate links on the canonical page (source of truth) page
second argument are the locales to generate the alternates for
parameters will be used in building the final url



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'app/helpers/www_helper.rb', line 76

def build_canonical_paths(url, locales: %i[en-US en-CA], parameters: nil, request_url: nil)
  parameters = parameters&.delete_if { |k, v| v.blank? } # Removes empty elements
  capture do
    c_url = cms_link(url, host: WEB_HOSTNAME, parameters: parameters, strip_params: true)
    concat tag.link(rel: 'canonical', href: c_url) + "\n".html_safe
    # We need to check that we are on the canonical url before rendering the alternates
    stripped_request_url = request_url ? cms_link(request_url, host: WEB_HOSTNAME, strip_params: true) : nil
    if stripped_request_url.nil? || c_url == stripped_request_url
      default_english_locale = locales.first
      locales.each do |locale|
        concat tag.link(rel: 'alternate', href: cms_link(url, locale, host: WEB_HOSTNAME, parameters: parameters, strip_params: true), hreflang: locale.downcase) + "\n".html_safe
      end
      concat tag.link(rel: 'alternate', href: cms_link(url, default_english_locale, host: WEB_HOSTNAME, parameters: parameters, strip_params: true), hreflang: 'en') + "\n".html_safe
      concat tag.link(rel: 'alternate', href: cms_link(url, default_english_locale, host: WEB_HOSTNAME, parameters: parameters, strip_params: true), hreflang: 'x-default') + "\n".html_safe
    end
  end
end

#page_section(id: nil, container: 'container-lg', padding: 'py-4', border: :bottom, background: :default, motion: nil, extra_classes: nil, data: {}) ⇒ Object

Renders a consistent page section wrapper with container, padding, borders, and optional animation

Examples:

Basic usage

<%= page_section(id: 'features', border: :bottom) do %>
  <h2>Features</h2>
<% end %>

With motion animation

<%= page_section(motion: :fade_up) do %>
  <h2>Animated content</h2>
<% end %>

Parameters:

  • id (String) (defaults to: nil)

    Optional section ID

  • container (String) (defaults to: 'container-lg')

    Container class (default: 'container-lg')

  • padding (String) (defaults to: 'py-4')

    Padding class (default: 'py-4')

  • border (Symbol) (defaults to: :bottom)

    Border style (:none, :top, :bottom, :both) - defaults to :bottom

  • background (Symbol) (defaults to: :default)

    Background style (:default, :light, :mint_green, etc.)

  • motion (Symbol, Hash) (defaults to: nil)

    Motion preset or custom options

  • extra_classes (String) (defaults to: nil)

    Additional CSS classes

  • block (Block)

    Section content

  • data (Hash{Symbol => Object}) (defaults to: {})


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'app/helpers/www_helper.rb', line 23

def page_section(id: nil, container: 'container-lg', padding: 'py-4', border: :bottom,
                 background: :default, motion: nil, extra_classes: nil, data: {}, &)
  # Motion presets for common animations
  motion_opts = case motion
                when :fade_up
                  { animation: 'fadeInUp', distance: 70, duration: 0.8 }
                when :fade_left
                  { animation: 'fadeInLeft', distance: 60, duration: 0.8 }
                when :fade_right
                  { animation: 'fadeInRight', distance: 60, duration: 0.8 }
                when :zoom
                  { animation: 'zoomPop', duration: 0.8 }
                when :pulse
                  { animation: 'pulse', duration: 1.2 }
                when Hash
                  motion
                end

  render(Www::PageSectionComponent.new(
    id: id,
    container: container,
    padding: padding,
    border: border,
    background: background,
    motion: motion_opts,
    extra_classes: extra_classes,
    data: data
  ), &)
end

#report_record_errors(record_errors) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'app/helpers/www_helper.rb', line 53

def report_record_errors(record_errors)
  errors = []
  errors << flash[:error] if flash[:error].present?
  flash[:error] = nil
  [record_errors].flatten.each do |record|
    errors += record.errors.full_messages if record.errors.any?
    record.errors.clear
  end
  return unless errors.present?

  formatted_message = errors.map { |e| tag.span(e, class: 'error_notice') }.join('<br>').html_safe
  "reportError('Errors','#{j(formatted_message)}')".html_safe
end

#roof_deicing_benefitsObject



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'app/helpers/www_helper.rb', line 94

def roof_deicing_benefits
  [
    { icon: 'icicles', title: 'Prevent Ice Dams',
      description: 'Heating cables in valleys and eaves stop ice dams before they form, protecting your roof and interior.' },
    { icon: 'droplet-slash', title: 'Stop Water Damage',
      description: 'Ice dams force water under shingles, causing leaks, mold, and structural rot. Deicing eliminates the root cause.' },
    { icon: 'house-crack', title: 'Protect Your Roof',
      description: 'Heavy ice loads stress gutters, fascia, and shingles—heating cables prevent costly damage.' },
    { icon: 'bolt', title: 'Automatic Operation',
      description: 'Smart sensors detect temperature and moisture, activating the system only when needed.' },
    { icon: 'shield-halved', title: 'Proven Reliability',
      description: 'WarmlyYours deicing cables are UL/CSA listed and backed by a manufacturer warranty.' },
    { icon: 'badge-dollar', title: 'Affordable to Operate',
      description: 'Self-regulating cables adjust output based on temperature, minimizing energy use.' }
  ]
end