connections/hub.ex
Hub
The company's systems arranged around one hub, each sending its records in.
# in the module that renders the template
use EHVisuals
<div class="h-96 rounded-xl border border-border">
<.connections_hub animated />
</div>
Props
| Prop | Type | Default | What it does |
|---|---|---|---|
systems |
list | ["ERP", "CRM", "Mail", "Sheets", "Bank", "WMS"] |
Three to eight short system names. |
center_label |
string | "EHOS" |
Frame props, shared by every composition
| Prop | Type | Default | What it does |
|---|---|---|---|
animated |
boolean | false |
Turns motion on. Without it the composition renders in its final, still state. |
trigger |
"mount" | "in-view" | "in-view-repeat" | "in-view" |
When the entrance plays: on page load, once when scrolled into view, or every time it comes back into view. |
hover |
boolean | false |
Enables the hover micro-interactions the composition supports. |
glow |
boolean | true |
The warm incandescent halo behind the composition. |
fade_out |
boolean | false |
Fades the bottom edge into the surface underneath. |
isometric |
boolean | false |
Tilts the composition into the isometric plane of the platform stack. |
theme |
"dark" | "light" | "dark" |
`dark` for the site canvas, `light` for the cream reversed surface. |
class |
string | nil |
Extra classes for the frame. |
rest |
global | — |
Any other HTML attribute, set on the frame. |
Source
Two files. Copy them into your app if you would rather own the code than depend on the library.
lib/eh_visuals/connections/hub.ex
defmodule EHVisuals.Connections.Hub do
@moduledoc """
The company's systems around one hub, each sending its records in.
"""
use EHVisuals.Composition,
name: "connections/hub",
title: "Hub",
description: "The company's systems arranged around one hub, each sending its records in."
attr(:systems, :list,
default: ~w(ERP CRM Mail Sheets Bank WMS),
doc: "Three to eight short system names."
)
attr(:center_label, :string, default: "EHOS")
attr(:label, :string, default: "Six company systems connected to EHOS in the middle")
frame_attrs()
@spec connections_hub(map()) :: Phoenix.LiveView.Rendered.t()
def connections_hub(assigns) do
count = max(length(assigns.systems), 1)
items =
for {name, index} <- Enum.with_index(assigns.systems) do
angle = (-90 + index * 360 / count) * :math.pi() / 180
%{
name: name,
index: index,
x: Float.round(200 + 150 * :math.cos(angle), 1),
y: Float.round(160 + 114 * :math.sin(angle), 1)
}
end
assigns =
assigns
|> assign(:items, items)
|> assign(:label_w, 14 + String.length(assigns.center_label) * 6.2)
~H"""
<.frame name="connections/hub" label={@label} {frame_opts(assigns)}>
<svg viewBox="0 0 400 320">
<g class="ehv-h-lift">
<ellipse class="ehv-line-faint ehv-a-fade ehv-i-1" cx="200" cy="160" rx="112" ry="84" />
<ellipse class="ehv-line-faint ehv-a-fade ehv-i-2" cx="200" cy="160" rx="66" ry="50" />
<line
:for={item <- @items}
class={"ehv-line ehv-a-draw ehv-i-#{item.index + 2}"}
x1={item.x}
y1={item.y}
x2="200"
y2="160"
pathLength="1"
/>
<g :if={@animated} class="ehv-smil ehv-a-fade ehv-i-12">
<circle :for={item <- @items} class="ehv-fill-lime" r="2.5">
<animate
attributeName="cx"
from={item.x}
to="200"
dur="2.8s"
begin={"#{item.index * 0.45}s"}
repeatCount="indefinite"
/>
<animate
attributeName="cy"
from={item.y}
to="160"
dur="2.8s"
begin={"#{item.index * 0.45}s"}
repeatCount="indefinite"
/>
<animate
attributeName="opacity"
values="0;1;1;0"
keyTimes="0;0.25;0.7;1"
dur="2.8s"
begin={"#{item.index * 0.45}s"}
repeatCount="indefinite"
/>
</circle>
</g>
<g :for={item <- @items} class={"ehv-a-pop ehv-i-#{item.index + 3}"}>
<rect
class="ehv-card ehv-connections-hub__chip"
x={item.x - 42}
y={item.y - 15}
width="84"
height="30"
rx="8"
/>
<text
class="ehv-mono ehv-t-2"
x={item.x}
y={item.y + 3.5}
font-size="9"
text-anchor="middle"
>
{String.upcase(item.name)}
</text>
</g>
<g class="ehv-a-pop">
<rect class="ehv-card-3" x="164" y="124" width="72" height="72" rx="18" />
<.mark x="172" y="132" size="56" />
</g>
<g class="ehv-a-fade ehv-i-4">
<rect
class="ehv-fill-canvas"
x={200 - @label_w / 2}
y="203"
width={@label_w}
height="16"
rx="5"
/>
<text class="ehv-mono ehv-t-lime" x="200" y="214" font-size="8.5" text-anchor="middle">
{String.upcase(@center_label)}
</text>
</g>
</g>
</svg>
</.frame>
"""
end
end
assets/css/connections/hub.css
/* connections/hub */
.ehv-connections-hub { --ehv-max-w: 440px; }
.ehv--hover .ehv-connections-hub__chip { transition: stroke 200ms var(--ehv-ease); }
.ehv--hover .ehv-connections-hub__chip:hover { stroke: var(--ehv-lime); }