Module: WwwHelper

Defined in:
app/helpers/www_helper.rb

Overview

View helper: www.

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



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

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

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

    Stimulus data attributes

Yields:

  • Section content



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
52
53
# File 'app/helpers/www_helper.rb', line 25

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



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

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 if errors.blank?

  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



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

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