kitmd 0.1.0

A terminal-based markdown and mermaid renderer/viewer using the Kitty graphics protocol
use std::collections::BTreeMap;

use crate::mermaid_engine::config::LayoutConfig;
use crate::mermaid_engine::ir::Graph;
use crate::mermaid_engine::theme::Theme;

use super::text::measure_label;
use super::{DiagramData, Layout, build_node_layout, resolve_node_style};

pub(super) fn compute_radar_layout(graph: &Graph, theme: &Theme, config: &LayoutConfig) -> Layout {
    const WIDTH: f32 = 680.0;
    const HEIGHT: f32 = 680.0;
    const CENTER_X: f32 = WIDTH / 2.0;
    const CENTER_Y: f32 = HEIGHT / 2.0;
    const MAX_RADIUS: f32 = 290.0;
    const LEGEND_BOX_SIZE: f32 = 11.0;
    const LEGEND_GAP: f32 = 3.0;

    let legend_offset = MAX_RADIUS * 0.875;
    let legend_base_x = CENTER_X + legend_offset;
    let legend_base_y = CENTER_Y - legend_offset;
    let legend_row_height = theme.font_size + 6.0;

    let mut node_ids: Vec<String> = graph.nodes.keys().cloned().collect();
    node_ids.sort_by(|a, b| {
        let order_a = graph.node_order.get(a).copied().unwrap_or(usize::MAX);
        let order_b = graph.node_order.get(b).copied().unwrap_or(usize::MAX);
        order_a.cmp(&order_b).then_with(|| a.cmp(b))
    });

    let mut nodes = BTreeMap::new();
    for (idx, node_id) in node_ids.iter().enumerate() {
        let Some(node) = graph.nodes.get(node_id) else {
            continue;
        };
        let label = measure_label(&node.label, theme, config);
        let width = LEGEND_BOX_SIZE + LEGEND_GAP + label.width;
        let height = label.height.max(LEGEND_BOX_SIZE);
        let mut style = resolve_node_style(node.id.as_str(), graph);
        if style.stroke.is_none() {
            style.stroke = Some("none".to_string());
        }
        if style.stroke_width.is_none() {
            style.stroke_width = Some(0.0);
        }
        let mut nl = build_node_layout(node, label, width, height, style, graph);
        nl.x = legend_base_x;
        nl.y = legend_base_y + idx as f32 * legend_row_height;
        nodes.insert(node.id.clone(), nl);
    }

    Layout {
        kind: graph.kind,
        nodes,
        edges: Vec::new(),
        subgraphs: Vec::new(),
        width: WIDTH,
        height: HEIGHT,
        diagram: DiagramData::Graph {
            state_notes: Vec::new(),
        },
    }
}