BEM class builder utilities for Pure Admin components.
All Pure Admin CSS classes follow BEM naming: pa-{block}, pa-{block}--{modifier},
pa-{block}__{element}.
Summary
Functions
Builds a CSS class string from a base class and a list of conditional modifiers.
Adds a BEM modifier class if the condition is truthy.
Returns url if it uses a safe scheme, otherwise fallback (defaults to
"#"). Phoenix's HEEx auto-escapes attribute values but does not
validate URL schemes, so a javascript:/data:/vbscript: URL bound to
href= will execute when clicked.
Functions
Builds a CSS class string from a base class and a list of conditional modifiers.
Examples
iex> PureAdmin.Helpers.build_classes("pa-btn", [{"pa-btn--primary", true}, {"pa-btn--sm", false}])
"pa-btn pa-btn--primary"
iex> PureAdmin.Helpers.build_classes("pa-btn", [{"pa-btn--primary", true}], "extra-class")
"pa-btn pa-btn--primary extra-class"
Adds a BEM modifier class if the condition is truthy.
Examples
iex> PureAdmin.Helpers.maybe_modifier("pa-btn", "primary", "primary")
"pa-btn--primary"
iex> PureAdmin.Helpers.maybe_modifier("pa-btn", nil, nil)
nil
Returns url if it uses a safe scheme, otherwise fallback (defaults to
"#"). Phoenix's HEEx auto-escapes attribute values but does not
validate URL schemes, so a javascript:/data:/vbscript: URL bound to
href= will execute when clicked.
Call this at the boundary where a URL could be user-controlled — e.g.
favourite links, user profile bios, CMS-edited nav items — before passing
the value to any href= attribute.
Deny-list, not allow-list — the goal is to block the four URL schemes
browsers will execute as script, not to second-guess which schemes your
app supports. So mailto:, tel:, sms:, deep-link schemes like
slack:// / intent:// / myapp://, and relative paths all pass
through unchanged.
Rejected schemes (returns fallback): javascript:, data:,
vbscript:, file:. Leading whitespace and case variations
(JavaScript:, javascript:) are handled.
Examples
iex> PureAdmin.Helpers.safe_url("https://example.com")
"https://example.com"
iex> PureAdmin.Helpers.safe_url("/dashboard")
"/dashboard"
iex> PureAdmin.Helpers.safe_url("javascript:alert(1)")
"#"
iex> PureAdmin.Helpers.safe_url("JavaScript:alert(1)")
"#"
iex> PureAdmin.Helpers.safe_url(" javascript:alert(1)")
"#"
iex> PureAdmin.Helpers.safe_url("data:text/html,<script>...</script>")
"#"
iex> PureAdmin.Helpers.safe_url("mailto:jane@example.com")
"mailto:jane@example.com"
iex> PureAdmin.Helpers.safe_url("tel:+420123456")
"tel:+420123456"
iex> PureAdmin.Helpers.safe_url("slack://channel?team=T1&id=C1")
"slack://channel?team=T1&id=C1"
iex> PureAdmin.Helpers.safe_url(nil)
"#"
iex> PureAdmin.Helpers.safe_url("#section")
"#section"
iex> PureAdmin.Helpers.safe_url("javascript:alert(1)", "/")
"/"