From f7fb72a4723d497efad276eb33def44d7648461c Mon Sep 17 00:00:00 2001 From: "brynary-fabro[bot]" <265161896+brynary-fabro[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 21:38:47 -0400 Subject: [PATCH] Style SVG output from `fabro graph` and API (#18) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR styles the SVG output from `fabro graph` and the API graph endpoints to match the polished look of the documentation SVGs. It introduces two internal functions in `graph.rs`: `inject_dot_style_defaults`, which inserts DOT-level defaults (transparent background, teal `#357f9e` node strokes, gray `#666666` edges, Helvetica font) after the first `{` in any DOT source, and `postprocess_svg`, which removes the Graphviz-generated white background polygon and injects a `"##; + +/// DOT graph-level defaults injected after the first `{`. +const DOT_STYLE_DEFAULTS: &str = r##" + bgcolor="transparent" + node [color="#357f9e", fontname="Helvetica", fontsize=12, fontcolor="#1a1a1a"] + edge [color="#666666", fontname="Helvetica", fontsize=10, fontcolor="#666666"] +"##; + static RANKDIR_RE: LazyLock = LazyLock::new(|| regex::Regex::new(r"rankdir\s*=\s*\w+").unwrap()); @@ -115,8 +134,52 @@ fn apply_direction<'a>(source: &'a str, direction: Option) -> Co } } -/// Spawn the `dot` command to render DOT source into the given format. -fn render_dot(source: &str, format: GraphFormat) -> anyhow::Result> { +/// Inject DOT graph-level style defaults (transparent background, teal nodes, +/// gray edges, Helvetica font) right after the first `{` in the DOT source. +/// Per-node/edge attributes override these defaults. +fn inject_dot_style_defaults(source: &str) -> String { + let Some(pos) = source.find('{') else { + return source.to_string(); + }; + let (before, after) = source.split_at(pos + 1); + format!("{before}{DOT_STYLE_DEFAULTS}{after}") +} + +/// Post-process raw SVG output from Graphviz: +/// 1. Remove the white background `` element +/// 2. Insert a dark-mode `