figma_html/
lib.rs

1use std::io::Write;
2
3use figma_schema::Node;
4use html_escape::{encode_style, encode_text};
5
6use self::intermediate_node::{
7    format_css, CSSVariable, CSSVariablesMap, HtmlFormatter, IntermediateNode,
8};
9
10mod css_properties;
11mod intermediate_node;
12
13pub fn file_collect_css_variables(file: &figma_schema::File) -> CSSVariablesMap {
14    file.styles
15        .iter()
16        .map(|(key, style)| {
17            (
18                key.as_str(),
19                CSSVariable {
20                    name: format!(
21                        "--{}",
22                        style.name.replace(|c: char| !c.is_alphanumeric(), "-")
23                    ),
24                    value: None,
25                },
26            )
27        })
28        .collect()
29}
30
31pub fn find_figma_node_by_id<'a>(
32    file: &'a figma_schema::File,
33    node_id: &str,
34) -> Option<&'a figma_schema::Node> {
35    let (node, _) = file
36        .document
37        .depth_first_stack_iter()
38        .find(|(n, _)| n.id == node_id)?;
39    Some(node)
40}
41
42pub fn figma_node_to_intermediate_node<'a>(
43    node: &'a Node,
44    css_variables: &mut CSSVariablesMap,
45) -> IntermediateNode<'a> {
46    IntermediateNode::from_figma_node(node, None, css_variables)
47}
48
49pub fn intermediate_node_to_html_writer(
50    writer: &mut impl Write,
51    node: &IntermediateNode,
52    css_variables: &CSSVariablesMap,
53) -> Result<(), std::io::Error> {
54    let mut naive_css = "margin: 0;".to_string();
55    for v in css_variables.values() {
56        if let Some(value) = v.value.as_deref() {
57            naive_css.push_str(&v.name);
58            naive_css.push_str(": ");
59            naive_css.push_str(value);
60            naive_css.push(';');
61        }
62    }
63
64    let body_css = format_css(3, &naive_css).unwrap_or_default();
65
66    writeln!(
67        writer,
68        r#"<!DOCTYPE html>
69<html
70  ><head
71    ><meta charset="utf-8" /><title>{}</title
72    ><style type="text/css">
73      body {{{}}}
74    </style></head
75  ><body
76    >{}</body
77  ></html
78>"#,
79        encode_text(&node.figma.as_ref().map(|f| f.name).unwrap_or("")),
80        encode_style(&body_css),
81        HtmlFormatter {
82            intermediate_node: node,
83            nesting_depth: 2
84        }
85    )
86}