Module: ActsAsCalculatorEditor::ApplicationHelper

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

Constant Summary collapse

"rounded-md px-3 py-1.5 font-medium transition-colors"

Instance Method Summary collapse

Instance Method Details

#button_class(variant = :primary) ⇒ Object



62
63
64
65
66
67
68
69
70
71
# File 'app/helpers/acts_as_calculator_editor/application_helper.rb', line 62

def button_class(variant = :primary)
  base = "inline-flex items-center justify-center rounded-md px-3 py-2 text-sm font-medium " \
         "transition-colors focus:outline-none focus:ring-2 focus:ring-offset-1"
  variants = {
    primary: "bg-slate-900 text-white hover:bg-slate-700 focus:ring-slate-400",
    danger: "bg-white text-red-700 border border-red-300 hover:bg-red-50 focus:ring-red-300",
    secondary: "bg-white text-slate-700 border border-slate-300 hover:bg-slate-50 focus:ring-slate-300"
  }
  "#{base} #{variants.fetch(variant, variants[:secondary])}"
end

#calculator_function_namesObject

Derived at runtime, never hardcoded. docs/core-gem-contract.md §5 is explicit about why: a host app may register its own functions into the same registry, so a list copied into JavaScript goes stale the moment somebody does. The autocomplete and the "unknown function" colouring both read this.

Dentaku::AST::Function.registry holds the builtins (57 of them); the gem's own FunctionRegistry.default holds bracket, progressive_bracket, round_currency and prorate plus anything the host added. Names come back in mixed shapes across the two, so they are folded to strings and uniqued case-insensitively — matching Dentaku's own case-insensitive resolution.



15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'app/helpers/acts_as_calculator_editor/application_helper.rb', line 15

def calculator_function_names
  @calculator_function_names ||= begin
    gem_functions = ActsAsCalculator::FunctionRegistry.default.to_a.map { |fn| fn.name.to_s }
    builtins = Dentaku::AST::Function.registry.keys.map(&:to_s)

    (gem_functions + builtins).uniq(&:downcase).sort
  rescue StandardError
    # A registry shape change upstream must not take the whole form down with it — the
    # editor degrades to "no autocomplete", and the server-side check still catches an
    # undefined function name.
    []
  end
end

Turbo must not touch a file response: it has no way to render one, and swallowing the navigation leaves the operator on the page with nothing downloaded.



31
32
33
# File 'app/helpers/acts_as_calculator_editor/application_helper.rb', line 31

def export_link_options(extra = {})
  { data: { turbo: false } }.deep_merge(extra)
end

#field_class(extra = nil) ⇒ Object

Shared input chrome, so a field looks the same on every form without each view restating a dozen utility classes.



47
48
49
50
51
52
# File 'app/helpers/acts_as_calculator_editor/application_helper.rb', line 47

def field_class(extra = nil)
  base = "block w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-sm " \
         "shadow-sm placeholder:text-slate-400 focus:border-slate-500 focus:outline-none " \
         "focus:ring-2 focus:ring-slate-200 disabled:bg-slate-100 read-only:bg-slate-100"
  [base, extra].compact.join(" ")
end

#hint_classObject



58
59
60
# File 'app/helpers/acts_as_calculator_editor/application_helper.rb', line 58

def hint_class
  "mt-1 block text-xs text-slate-500"
end

#label_classObject



54
55
56
# File 'app/helpers/acts_as_calculator_editor/application_helper.rb', line 54

def label_class
  "mb-1 block text-sm font-medium text-slate-700"
end


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

def nav_class(current)
  if current
    "#{NAV_BASE} bg-slate-900 text-white"
  else
    "#{NAV_BASE} text-slate-600 hover:bg-slate-100 hover:text-slate-900"
  end
end

#status_badge(status) ⇒ Object

A status pill for a formula version or template row.



74
75
76
77
78
79
80
81
82
83
# File 'app/helpers/acts_as_calculator_editor/application_helper.rb', line 74

def status_badge(status)
  palette = {
    "active" => "bg-emerald-100 text-emerald-800",
    "draft" => "bg-amber-100 text-amber-800",
    "retired" => "bg-slate-200 text-slate-600"
  }
  classes = "inline-flex rounded-full px-2 py-0.5 text-xs font-medium " \
            "#{palette.fetch(status.to_s, "bg-slate-200 text-slate-600")}"
  tag.span(status, class: classes)
end