PhoenixKitDashboards.Web.BuilderLive (PhoenixKitDashboards v0.1.0)

Copy Markdown View Source

The dashboard builder — a responsive, server-rendered grid of widgets that can be added from the catalog, reordered, resized, configured, and removed.

Phoenix-first, server-authoritative

The grid is plain HEEx + a CSS grid: each widget instance is anchored at its placement's x/y cells (grid-column/-row: <line> / span <n>) on the active breakpoint's column grid. It renders — and is fully readable — without any JavaScript. The server owns the canonical layout (the JSONB layout list); every mutation re-renders normally (no phx-update="ignore"), so adding/removing/moving/resizing a widget is live.

There are two render modes, derived from the dashboard's type (fixed at creation — config["type"] = "grid" | "pixel") via Dashboard.layout_mode/1 (legacy config["mode"] still maps):

  • grid — explicit cell placement on a responsive column grid: each widget is anchored at x/y cells and spans w×h — place it ANYWHERE (gaps are fine), widgets never overlap. Drag by the grip (DashboardGridDrag, cell- snapped live preview), resize by the corner (snaps + grows until blocked).
  • free — an absolute pixel canvas: drag and resize anywhere, exact px, no snapping. Widgets may overlap — deliberately, via the per-widget bring-to-front / send-to-back controls (a z key in the pixel map). Uses separate fx/fy/fw/fh px keys so the two layouts never disturb each other. The DashboardFreeFit hook scales the whole canvas to fill the available width (fit-to-width, so the exact layout is preserved on any screen — it just shrinks on a phone); vertical overflow scrolls.

Widgets with a refresh_interval are re-queried by a host-driven :refresh_tick loop.

Custom hooks (shipped via js_sources/0): DashboardGridDrag (grid cell placement — the widget follows the drag cell-by-cell, never onto an occupied spot), DashboardCatalogDrag (drag a widget type OUT of the catalog and drop it on a grid cell or canvas point; a plain click still adds at the first free spot), DashboardFreeDrag (free-canvas move via left/top) and DashboardResize (corner grip .pk-resize-handle — px in free mode; cell-snap clamped by neighbours in grid). The non-hook fallback is the Settings modal's inputs (px size + X/Y position in free; cell size + Column/Row position in grid), all server-driven. Every layout-tweak handler is guarded so a hostile/malformed event can't crash or brick the builder.