Module: RoundhouseUi::Icons
- Defined in:
- lib/roundhouse_ui/icons.rb
Overview
Icons as inline SVG. No font, no request, no CSP change, and identical on
every platform — which the Unicode glyphs these replace were not: ⛁ and
☷ have no glyph at all on older Windows, ⚙/☾/⚠ get substituted for
emoji on some platforms, and ▦ and ▤ are indistinguishable at 16px.
Hosts that already ship an icon font can use it instead:
RoundhouseUi.icons = :font_awesome
RoundhouseUi.icons = { dashboard: "fa-solid fa-gauge-high", ... }
Roundhouse never loads a font itself in either case. It emits class names and the host's existing pipeline supplies the glyphs, which is what keeps the self-contained CSP intact.
Constant Summary collapse
- VIEWBOX =
"0 0 24 24".freeze
- ATTRS =
Geometric on purpose: an operations console is not the place for personality, and a 1.9 stroke stays legible at 15px.
%(viewBox="#{VIEWBOX}" width="15" height="15" fill="none" stroke="currentColor" ) + %(stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false")
- PATHS =
{ dashboard: '<rect x="3" y="3" width="7.5" height="7.5" rx="1.4"/><rect x="13.5" y="3" width="7.5" height="7.5" rx="1.4"/><rect x="3" y="13.5" width="7.5" height="7.5" rx="1.4"/><rect x="13.5" y="13.5" width="7.5" height="7.5" rx="1.4"/>', queues: '<path d="M4 7h16M4 12h16M4 17h10"/>', retries: '<path d="M20 11a8 8 0 1 0-2.5 6.9"/><path d="M20 5v6h-6"/>', dead: '<circle cx="12" cy="12" r="8.4"/><path d="M9 9l6 6M15 9l-6 6"/>', errors: '<path d="M12 4.2 2.8 20h18.4L12 4.2Z"/><path d="M12 10v4"/><circle cx="12" cy="17" r=".6" fill="currentColor"/>', busy: '<circle cx="12" cy="12" r="8.4"/><path d="M12 3.6a8.4 8.4 0 0 1 0 16.8Z" fill="currentColor" stroke="none"/>', metrics: '<path d="M4 20V13M9.3 20V8M14.7 20v-6M20 20V4"/>', snapshots: '<ellipse cx="12" cy="6" rx="8" ry="3"/><path d="M4 6v6c0 1.7 3.6 3 8 3s8-1.3 8-3V6"/><path d="M4 12v6c0 1.7 3.6 3 8 3s8-1.3 8-3v-6"/>', audit: '<path d="M4 6h16M4 11h16M4 16h9"/><path d="M15.5 18.5l1.8 1.8 3.2-3.6"/>', settings: '<path d="M4 7h9M17 7h3M4 17h3M11 17h9"/><circle cx="15" cy="7" r="2.1"/><circle cx="7" cy="17" r="2.1"/>', scheduled: '<circle cx="12" cy="12" r="8.4"/><path d="M12 7.6V12l3.2 2"/>', workers: '<rect x="6.5" y="6.5" width="11" height="11" rx="1.6"/><path d="M10 3v3M14 3v3M10 18v3M14 18v3M3 10h3M3 14h3M18 10h3M18 14h3"/>', capsules: '<rect x="3.5" y="3.5" width="7" height="7" rx="1.3"/><rect x="13.5" y="3.5" width="7" height="7" rx="1.3"/><rect x="3.5" y="13.5" width="7" height="7" rx="1.3"/><path d="M17 14v6M14 17h6"/>', redis: '<path d="M3.6 7.5 12 4l8.4 3.5L12 11 3.6 7.5Z"/><path d="M3.6 12 12 15.5 20.4 12"/><path d="M3.6 16.5 12 20l8.4-3.5"/>', enqueue: '<path d="M12 5v14M5 12h14"/>', width: '<path d="M3 12h18"/><path d="M7 8l-4 4 4 4M17 8l4 4-4 4"/>', theme: '<path d="M20 14.5A8.5 8.5 0 1 1 9.5 4a6.8 6.8 0 0 0 10.5 10.5Z"/>', pause: '<path d="M9.5 5v14M14.5 5v14"/>', delete: '<path d="M5 7h14"/><path d="M9 7V4.6h6V7"/><path d="M6.5 7l1 12.4h9L18 7"/>', ok: '<path d="M4.5 12.5l5 5L20 6.5"/>', warn: '<path d="M12 4.2 2.8 20h18.4L12 4.2Z"/><path d="M12 10v4"/><circle cx="12" cy="17" r=".6" fill="currentColor"/>', stalled: '<circle cx="12" cy="12" r="8.4"/><path d="M8.5 12h7"/>', search: '<circle cx="10.5" cy="10.5" r="6.5"/><path d="M15.4 15.4 21 21"/>', # A funnel, for "find more like this". Deliberately not the magnifier: the # search box is one control and this is another, and giving them the same # glyph is what made the row control ambiguous. A funnel also cannot be # misread as "duplicate", which two stacked shapes would be with Edit # sitting directly beside it. filter: '<path d="M4 5h16l-6.2 7.3v5.9L10.2 21v-8.7L4 5Z"/>', runbook: '<path d="M5 4h9l5 5v11H5Z"/><path d="M14 4v5h5"/><path d="M8.5 13h7M8.5 16.5h4.5"/>', # Default trace glyph: an external-link arrow. Roundhouse ships no vendor # logo — see Observability adapters, which may supply their own mark. trace_out: '<path d="M14 4h6v6"/><path d="M20 4 11 13"/><path d="M18 14v4.5A1.5 1.5 0 0 1 16.5 20h-11A1.5 1.5 0 0 1 4 18.5v-11A1.5 1.5 0 0 1 5.5 6H10"/>' }.freeze
- FONT_AWESOME =
For hosts that already load FontAwesome Free. Names chosen from the free set so nothing here needs a Pro licence.
{ dashboard: "fa-solid fa-gauge-high", queues: "fa-solid fa-layer-group", retries: "fa-solid fa-rotate-right", dead: "fa-solid fa-circle-xmark", errors: "fa-solid fa-triangle-exclamation", busy: "fa-solid fa-circle-half-stroke", metrics: "fa-solid fa-chart-simple", snapshots: "fa-solid fa-database", audit: "fa-solid fa-list-check", settings: "fa-solid fa-sliders", scheduled: "fa-regular fa-clock", workers: "fa-solid fa-microchip", capsules: "fa-solid fa-table-cells-large", redis: "fa-solid fa-cubes-stacked", enqueue: "fa-solid fa-plus", width: "fa-solid fa-arrows-left-right", theme: "fa-solid fa-moon", pause: "fa-solid fa-pause", delete: "fa-solid fa-trash-can", ok: "fa-solid fa-check", warn: "fa-solid fa-triangle-exclamation", stalled: "fa-solid fa-minus", search: "fa-solid fa-magnifying-glass", runbook: "fa-regular fa-file-lines", filter: "fa-solid fa-filter", trace_out: "fa-solid fa-arrow-up-right-from-square" }.freeze
Class Method Summary collapse
-
.class_name(value) ⇒ Object
Host-supplied, so it is never marked html_safe — the caller escapes it into a class attribute.
-
.markup(name, config = RoundhouseUi.icons) ⇒ Object
An icon's markup, or nil when the name is unknown — an unknown name draws nothing rather than raising, so a typo in a host's mapping cannot take a page down.
- .svg(key) ⇒ Object
Class Method Details
.class_name(value) ⇒ Object
Host-supplied, so it is never marked html_safe — the caller escapes it into a class attribute.
100 101 102 |
# File 'lib/roundhouse_ui/icons.rb', line 100 def class_name(value) value.presence end |
.markup(name, config = RoundhouseUi.icons) ⇒ Object
An icon's markup, or nil when the name is unknown — an unknown name draws nothing rather than raising, so a typo in a host's mapping cannot take a page down.
82 83 84 85 86 87 88 89 |
# File 'lib/roundhouse_ui/icons.rb', line 82 def markup(name, config = RoundhouseUi.icons) key = name.to_s.to_sym case config when :font_awesome then class_name(FONT_AWESOME[key]) when Hash then class_name(config[key] || config[name.to_s]) else svg(key) end end |