Packages

Native Phoenix LiveView UI components — server-rendered SVG charts and more, themeable via CSS variables (Fluxon-compatible). No React, no JS chart libraries.

Current section

Files

Jump to
lantern_ui README.md
Raw

README.md

# LanternUI
Native Phoenix LiveView UI components — server-rendered SVG charts (and more over
time), themeable via CSS variables. **No React, no JavaScript charting library.**
Part of the lantern family: [`lantern`](https://github.com/go9/lantern) is an
embeddable Postgres table viewer; `lantern_ui` is the UI component set.
## What's here
- `LanternUI.Charts.area_chart/1` — time-series area + line with an interactive
crosshair/tooltip.
- `LanternUI.Charts.sparkline/1` — compact trend, no axes.
- `LanternUI.Charts.bar_chart/1` — categorical bars.
- `LanternUI.Charts.line_chart/1` — multi-series time-series lines with a legend
and a shared crosshair tooltip (built for resource/monitoring metrics).
- `LanternUI.Charts.Geometry` — pure scaling / "nice" ticks / SVG path helpers.
Geometry is computed in Elixir, so charts re-render through normal LiveView
assigns. The only client JS is one small hook (`ChartHover`) for the area chart's
tooltip.
## Installation
From Hex (once published):
```elixir
def deps do
[{:lantern_ui, "~> 0.1"}]
end
```
Or from git while iterating:
```elixir
{:lantern_ui, "~> 0.3"}
# or track main:
# {:lantern_ui, github: "go9/lantern-ui"}
```
## Usage
```heex
<LanternUI.Charts.area_chart
id="price-history"
series={[%{date: "2024-01-01", value: 24.5}, %{date: "2024-02-01", value: 27.1}]}
value_format={:currency}
height={250}
/>
<LanternUI.Charts.sparkline id="trend" series={[3, 5, 4, 6, 8, 7, 9]} />
<LanternUI.Charts.bar_chart
id="sales"
series={[%{label: "Q1", value: 42}, %{label: "Q2", value: 31}]}
/>
<LanternUI.Charts.line_chart
id="pod-cpu"
series={[
%{label: "web-1", color: "var(--color-primary)",
points: [{~U[2024-11-20 14:00:00Z], 0.25}, {~U[2024-11-20 14:05:00Z], 0.31}]},
%{label: "web-2", points: [{~U[2024-11-20 14:00:00Z], 0.18}, {~U[2024-11-20 14:05:00Z], 0.22}]}
]}
value_format={&"#{&1} cores"}
/>
```
`line_chart` `series`: a list of `%{label, color, points: [{datetime, number}]}`
(`color` optional; `points` accept `{datetime, value}` tuples or `%{time, value}`
maps; datetime = `DateTime`/`NaiveDateTime`/`Date`/ISO-8601 string).
`area_chart` `series`: a list of `%{date: iso8601 | Date, value: number}`.
## JS hook (required for area_chart hover)
`area_chart` uses `ChartHover` and `line_chart` uses `LineHover` for their
crosshair/tooltips — both ship in `LanternHooks`, so the single import below
registers them. In `assets/js/app.js`:
```js
import LanternHooks from "../../deps/lantern_ui/priv/static/lantern_ui_hooks.js"
let Hooks = { ...LanternHooks /* , ...yourOtherHooks */ }
let liveSocket = new LiveSocket("/live", Socket, { params: {/* ... */}, hooks: Hooks })
```
`sparkline` and `bar_chart` need no JavaScript.
## Theming
Components read colors from CSS variables with chained fallbacks:
| Purpose | Variable chain |
|---|---|
| accent | `--lantern-accent``--color-primary-500``#3b82f6` |
| text | `--lantern-fg``--foreground``#111827` |
| muted text | `--lantern-fg-muted``--foreground-softer``#6b7280` |
| surface (tooltip) | `--lantern-surface``--background-base``#ffffff` |
Two stylesheets ship in `priv/static`:
- **`lantern_ui.css` — component styles, always import it** when using any
`lui-*` component (button, pickers, modal, dropdown, …). Charts don't need it.
- **`lantern_ui_theme.css` — the optional default theme** (tokens, light/dark,
density modes).
Pick per host:
- **Standalone / public?** Import both:
```css
/* assets/css/app.css */
@import "../../deps/lantern_ui/priv/static/lantern_ui.css";
@import "../../deps/lantern_ui/priv/static/lantern_ui_theme.css";
```
- **Using Fluxon** (or any system defining design tokens)? Import only the
component styles and bridge `--lantern-*` onto your tokens (full example in
the `lantern_ui.css` header). Charts need neither — they inherit through
their built-in fallbacks.
- **Recolor** by setting any `--lantern-*` variable yourself.
## Value formatting
`area_chart` and `bar_chart` accept `value_format`: `:number` (default),
`:currency` (USD-style `$` prefix), or a 1-arity function `(number -> String.t())`.
Any other value is treated as `:number`. Custom-function output is rendered as
plain text — it is HTML-escaped before it reaches the tooltip.
## License
MIT — see [LICENSE](LICENSE).