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}