mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-29 04:46:50 -06:00
Merge pull request #1011 from lucasmartins-ai/feat/tailwind-output
Dev Mode: React + Tailwind page code and Tailwind theme export
This commit is contained in:
@@ -18,7 +18,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
spec!(
|
||||
"variable.export",
|
||||
"Export variables",
|
||||
"{collections? [ids or names; default every collection of this file, not library copies], format? (json (default): the local variables JSON that variable.import reads | css: custom properties, the default mode on :root and each other mode on [data-<collection>=\"<mode>\"]; numbers in px unless layers or scopes use them as opacity or font weight), path? (write it there)} → {text}, or {path} when written",
|
||||
"{collections? [ids or names; default every collection of this file, not library copies], format? (json (default): the local variables JSON that variable.import reads | css: custom properties, the default mode on :root and each other mode on [data-<collection>=\"<mode>\"]; numbers in px unless layers or scopes use them as opacity or font weight | tailwind: a Tailwind CSS v4 stylesheet, the default mode as an @theme block named the way inspect.code's tailwind utilities read them: --color-*, --radius-*, --text-*, --spacing-*, --font-*, unique per file), path? (write it there)} → {text}, or {path} when written",
|
||||
false,
|
||||
export
|
||||
),
|
||||
@@ -46,8 +46,9 @@ fn export(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let text = match string(p, "format").as_deref().unwrap_or("json") {
|
||||
"json" => serde_json::to_string_pretty(&figcraft_format::rest::export_variables(&doc.variables, &colls))
|
||||
.map_err(|e| EngineError::Other(e.to_string()))?,
|
||||
"css" => css(doc, &colls),
|
||||
_ => return Err(bad(cmd, "format: json|css")),
|
||||
"css" => css(doc, &colls, false),
|
||||
"tailwind" => css(doc, &colls, true),
|
||||
_ => return Err(bad(cmd, "format: json|css|tailwind")),
|
||||
};
|
||||
match string(p, "path") {
|
||||
Some(path) => {
|
||||
@@ -66,16 +67,25 @@ fn css_safe(text: &str) -> String {
|
||||
/// Each collection's variables as custom properties (named as generated code names them): the
|
||||
/// default mode's values on `:root`, every other mode's on `[data-<collection>="<mode>"]`;
|
||||
/// aliases are `var(--name)`.
|
||||
fn css(doc: &Document, colls: &[&Collection]) -> String {
|
||||
fn css(doc: &Document, colls: &[&Collection], tailwind: bool) -> String {
|
||||
let vars = &doc.variables;
|
||||
// Tailwind theme names, unique per file and the same ones page code reads.
|
||||
let theme = crate::tailwind::Theme::new(doc);
|
||||
let name = |v: &Variable| if tailwind { theme.name(v) } else { css_var_of(v) };
|
||||
// Lengths need a unit where CSS reads them (`border-radius: var(--radius)`); opacity and
|
||||
// font weight don't.
|
||||
let roles = crate::token_roles::Roles::new(doc);
|
||||
let mut out = String::new();
|
||||
let mut out = if tailwind { "@import \"tailwindcss\";\n\n".to_string() } else { String::new() };
|
||||
for c in colls {
|
||||
let attr = css_var_name(&c.name);
|
||||
for (i, m) in c.modes.iter().enumerate() {
|
||||
let sel = if i == 0 { ":root".to_string() } else { format!("[data-{}=\"{}\"]", attr.trim_start_matches('-'), css_safe(&m.name)) };
|
||||
let sel = match i {
|
||||
// `static`: Tailwind otherwise drops theme variables no utility uses, and pages also
|
||||
// read them through `var()` and `(--name)` utilities.
|
||||
0 if tailwind => "@theme static".to_string(),
|
||||
0 => ":root".to_string(),
|
||||
_ => format!("[data-{}=\"{}\"]", attr.trim_start_matches('-'), css_safe(&m.name)),
|
||||
};
|
||||
out.push_str(&format!("/* {} · {} */\n{sel} {{\n", css_safe(&c.name), css_safe(&m.name)));
|
||||
for v in vars.variables.iter().filter(|v| v.collection == c.id) {
|
||||
let value = match v.values.get(&m.id) {
|
||||
@@ -85,12 +95,12 @@ fn css(doc: &Document, colls: &[&Collection]) -> String {
|
||||
Some(VariableValue::String(t)) => format!("\"{}\"", css_safe(t)),
|
||||
Some(VariableValue::Boolean(b)) => b.to_string(),
|
||||
Some(VariableValue::Alias(a)) => match vars.get(a) {
|
||||
Some(t) => format!("var({})", css_var_of(t)),
|
||||
Some(t) => format!("var({})", name(t)),
|
||||
None => continue,
|
||||
},
|
||||
None => continue,
|
||||
};
|
||||
out.push_str(&format!(" {}: {value};\n", css_var_of(v)));
|
||||
out.push_str(&format!(" {}: {value};\n", name(v)));
|
||||
}
|
||||
out.push_str("}\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user