diff --git a/artefact_kino/artefact_kino.livemd b/artefact_kino/artefact_kino.livemd index 2298981..4221ef8 100644 --- a/artefact_kino/artefact_kino.livemd +++ b/artefact_kino/artefact_kino.livemd @@ -107,10 +107,11 @@ of how many labels either artefact contains. An `Agent` node will be the same sh blue-green in a two-label artefact as it is in a ten-label one. You can follow a concept by colour across panels without thinking about it. -**Stable header height.** When an artefact carries a long description — a Cypher query or -a chapter summary — the header expands and the graph viewports in the two panels no longer -align. Pass `max_description_lines:` to cap the description to a fixed number of lines with -overflow hidden. Both panels keep the same height and the graphs line up. +**Stable header height.** When artefacts have descriptions of different lengths — or when +one has no description at all — the headers expand differently and the graph viewports no +longer align. Pass `description_lines:` to reserve a fixed-height description area of +exactly that many lines. Content is clipped if it is longer; the space is held empty if +there is no description. Both panels share the same header height and the graphs line up. ```elixir require Artefact @@ -146,8 +147,8 @@ integrated = ) Kino.Layout.grid([ - ArtefactKino.new(section, max_description_lines: 2), - ArtefactKino.new(integrated, max_description_lines: 2) + ArtefactKino.new(section, description_lines: 2), + ArtefactKino.new(integrated, description_lines: 2) ], columns: 2) ``` diff --git a/artefact_kino/lib/artefact_kino.ex b/artefact_kino/lib/artefact_kino.ex index 17d7677..bf871ad 100644 --- a/artefact_kino/lib/artefact_kino.ex +++ b/artefact_kino/lib/artefact_kino.ex @@ -28,18 +28,19 @@ defmodule ArtefactKino do Options: - `default:` — `:create` (default) or `:merge` - - `max_description_lines:` — integer; caps the description to this many - lines with overflow hidden. Useful when placing widgets side by side so - that long descriptions do not cause misaligned graph viewports. + - `description_lines:` — integer; reserves a fixed-height description area + of exactly this many lines. Content is clipped if longer; an empty area + is reserved if there is no description. Keeps side-by-side graph viewports + at the same height regardless of description length or presence. """ def new(%Artefact{} = artefact, opts \\ []) do Artefact.validate!(artefact) default = Keyword.get(opts, :default, :create) - max_description_lines = Keyword.get(opts, :max_description_lines, nil) - Kino.JS.new(__MODULE__, build_data(artefact, default, max_description_lines)) + description_lines = Keyword.get(opts, :description_lines, nil) + Kino.JS.new(__MODULE__, build_data(artefact, default, description_lines)) end - defp build_data(artefact, default, max_description_lines) do + defp build_data(artefact, default, description_lines) do %{ nodes: vis_nodes(artefact), edges: vis_edges(artefact), @@ -50,7 +51,7 @@ defmodule ArtefactKino do default: Atom.to_string(default), title: artefact.title || artefact.base_label || "Artefact", description: artefact.description, - max_description_lines: max_description_lines, + description_lines: description_lines, artefact_rows: artefact_rows(artefact), nodes_rows: nodes_rows(artefact), rels_rows: rels_rows(artefact) @@ -210,16 +211,21 @@ defmodule ArtefactKino do .replace(/"/g, """) .replace(/'/g, "'"); - const descStyle = data.max_description_lines - ? `font-size:11px;color:#888;margin-top:2px;font-style:italic;display:-webkit-box;-webkit-line-clamp:${data.max_description_lines};-webkit-box-orient:vertical;overflow:hidden;` - : `font-size:11px;color:#888;margin-top:2px;font-style:italic;white-space:pre-line;`; + const descHtml = (() => { + if (data.description_lines) { + const style = `font-size:11px;color:#888;margin-top:2px;font-style:italic;line-height:1.4;height:calc(${data.description_lines} * 1.4em);overflow:hidden;white-space:pre-line;`; + return `