Module: Collavre::ApplicationHelper

Defined in:
app/helpers/collavre/application_helper.rb

Constant Summary collapse

COLLAVRE_STYLESHEETS =

All Collavre engine stylesheets in load order. Host apps should call <%= collavre_stylesheets %> in their layout <head> instead of listing individual stylesheet_link_tags.

%w[
  collavre/design_tokens
  collavre/dark_mode
  collavre/gnb
  collavre/creatives
  collavre/actiontext
  collavre/activity_logs
  collavre/user_menu
  collavre/org_chart
  collavre/popup
  collavre/comments_popup
  collavre/code_highlight
  collavre/comment_versions
  collavre/mention_menu
  collavre/modal_dialog
  collavre/slide_view
  collavre/image_lightbox
  collavre/search_popup
].freeze
COLLAVRE_PRINT_STYLESHEETS =
%w[
  collavre/print
].freeze
SEMANTIC_TO_LEGACY =

Maps semantic token names to their legacy alias names. When custom themes inject semantic tokens on <body>, the legacy aliases defined on :root still resolve to :root’s light values. This map lets the theme injection template also emit legacy aliases so that CSS using old variable names (e.g. –color-section-bg) picks up custom values.

{
  "--surface-bg" => "--color-bg",
  "--surface-nav" => "--color-nav-bg",
  "--surface-section" => "--color-section-bg",
  "--surface-input" => "--color-input-bg",
  "--surface-btn" => "--color-btn-bg",
  "--surface-secondary" => "--color-secondary-background",
  "--text-primary" => "--color-text",
  "--text-muted" => "--color-muted",
  "--text-on-btn" => "--color-btn-text",
  "--text-nav" => "--color-nav-text",
  "--text-nav-btn" => "--color-nav-btn-text",
  "--text-chat-btn" => "--color-chat-btn-text",
  "--text-on-badge" => "--color-badge-text",
  "--text-input" => "--color-input-text",
  "--color-brand" => "--color-complete",
  "--color-active" => "--color-secondary-active",
  "--border-color" => "--color-border",
  "--border-drag-over" => "--color-drag-over",
  "--border-drag-edge" => "--color-drag-over-edge"
}.freeze

Instance Method Summary collapse

Instance Method Details

#body_theme_classObject

Returns the body CSS class for the current user’s theme. Custom themes get “light-mode” to disable OS dark mode overrides, ensuring the custom theme controls all colors regardless of OS setting.



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'app/helpers/collavre/application_helper.rb', line 48

def body_theme_class
  theme = Current.user&.theme
  return "" if theme.blank?

  case theme
  when "dark"
    "dark-mode"
  when "light"
    "light-mode"
  else
    "light-mode" # Custom theme: neutralize OS dark mode
  end
end

#collavre_stylesheetsObject

Renders all Collavre engine stylesheet tags. Call this once in the host app’s layout <head> section.

<%= collavre_stylesheets %>


35
36
37
38
39
40
41
42
43
# File 'app/helpers/collavre/application_helper.rb', line 35

def collavre_stylesheets
  tags = COLLAVRE_STYLESHEETS.map do |sheet|
    stylesheet_link_tag(sheet)
  end
  tags += COLLAVRE_PRINT_STYLESHEETS.map do |sheet|
    stylesheet_link_tag(sheet, media: "print")
  end
  safe_join(tags, "\n    ")
end

#default_theme_stylesObject

Renders CSS for admin-configured default themes (light/dark mode) Only applies when the user has no personal theme set



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'app/helpers/collavre/application_helper.rb', line 64

def default_theme_styles
  return "" if Current.user&.theme.present?

  light_theme = SystemSetting.default_light_theme
  dark_theme = SystemSetting.default_dark_theme
  return "" unless light_theme || dark_theme

  styles = []

  if light_theme
    styles << render_theme_media_query(light_theme, "light")
  end

  if dark_theme
    styles << render_theme_media_query(dark_theme, "dark")
  end

  safe_join(styles, "\n")
end

#legacy_alias_declarations(variables) ⇒ Object

Given a hash of semantic token variables, returns additional legacy alias declarations so old CSS picks up the custom theme values.



200
201
202
203
204
205
206
207
208
# File 'app/helpers/collavre/application_helper.rb', line 200

def legacy_alias_declarations(variables)
  aliases = {}
  variables.each do |key, value|
    if (legacy_name = SEMANTIC_TO_LEGACY[key])
      aliases[legacy_name] = value
    end
  end
  aliases
end

#render_extension_slot(slot, **locals) ⇒ Object

Render all partials registered for a named extension slot. Engines register their partials via Collavre::ViewExtensions.register. Returns empty string if no partials are registered for the slot.

<%= render_extension_slot(:creative_toolbar) %>
<%= render_extension_slot(:creative_modals, parent_creative: @parent_creative) %>


139
140
141
142
143
144
# File 'app/helpers/collavre/application_helper.rb', line 139

def render_extension_slot(slot, **locals)
  entries = Collavre::ViewExtensions.for_slot(slot)
  return safe_join([]) if entries.empty?

  safe_join(entries.map { |entry| render(partial: entry[:partial], locals: locals) })
end

#render_label_extra(label, **locals) ⇒ Object

Render a label-type-specific partial if one exists. Engines provide partials at collavre/labels/_type_underscore_suffix.html.erb Falls back to nil when no matching partial is found.

<%= render_label_extra(label, parent_creative: @parent_creative) %>
<%= render_label_suffix(label) %>


153
154
155
156
157
158
159
160
# File 'app/helpers/collavre/application_helper.rb', line 153

def render_label_extra(label, **locals)
  return nil if label.type.blank?

  partial = "collavre/labels/#{label.type.underscore}_extra"
  render(partial: partial, locals: locals.merge(label: label))
rescue ActionView::MissingTemplate
  nil
end

#render_label_suffix(label) ⇒ Object



162
163
164
165
166
167
168
169
# File 'app/helpers/collavre/application_helper.rb', line 162

def render_label_suffix(label)
  return nil if label.type.blank?

  partial = "collavre/labels/#{label.type.underscore}_suffix"
  render(partial: partial, locals: { label: label })
rescue ActionView::MissingTemplate
  nil
end

#user_json(user, email: false, ai_user: false) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
# File 'app/helpers/collavre/application_helper.rb', line 84

def user_json(user, email: false, ai_user: false)
  data = {
    id: user.id,
    name: user.display_name,
    avatar_url: user_avatar_url(user, size: 20),
    default_avatar: !user.avatar.attached? && user.avatar_url.blank?,
    initial: user.display_name&.at(0)&.upcase || "?"
  }
  data[:email] = user.email if email
  data[:ai_user] = user.ai_user? if ai_user
  data
end