diff --git a/src/core/sass/brand.ts b/src/core/sass/brand.ts index 480957b11e..d8121c6f9e 100644 --- a/src/core/sass/brand.ts +++ b/src/core/sass/brand.ts @@ -202,25 +202,37 @@ const brandColorLayer = ( }; }; +type BootstrapDefaultsConfig = { + uses?: string; + functions?: string; + defaults?: Record>; + mixins?: string; + rules?: string; +}; + const brandDefaultsBootstrapLayer = ( brand: Brand, ): SassLayer => { // Bootstrap Variables from brand.defaults.bootstrap - const brandBootstrap = brand?.data?.defaults?.bootstrap as unknown as Record< - string, - Record - >; + const brandBootstrap = brand?.data?.defaults + ?.bootstrap as unknown as BootstrapDefaultsConfig; const bsVariables: string[] = [ "/* Bootstrap variables from _brand.yml */", - '// quarto-scss-analysis-annotation { "action": "push", "origin": "_brand.yml defaults.bootstrap" }', + '// quarto-scss-analysis-annotation { "action": "push", "origin": "_brand.yml defaults.bootstrap.defaults" }', ]; - for (const bsVar of Object.keys(brandBootstrap)) { - if (bsVar === "version") { - continue; + const bsDefaults = brandBootstrap.defaults || ""; + if (typeof bsDefaults === "string") { + bsVariables.push(bsDefaults); + } else if (typeof bsDefaults === "object") { + for (const bsVar of Object.keys(bsDefaults)) { + bsVariables.push(`$${bsVar}: ${bsDefaults[bsVar]} !default;`); } - bsVariables.push( - `$${bsVar}: ${brandBootstrap[bsVar]} !default;`, + } else { + throw new Error( + "Invalid bootstrap defaults in _brand.yml or `brand`. " + + "`defaults.bootstrap.defaults` expects a string or a dictionary " + + "mapping Sass variables to default values." ); } bsVariables.push('// quarto-scss-analysis-annotation { "action": "pop" }'); @@ -253,20 +265,36 @@ const brandDefaultsBootstrapLayer = ( continue; } - bsColors.push( - `$${colorKey}: ${brand.getColor(colorKey)} !default;`, - ); + bsColors.push(`$${colorKey}: ${brand.getColor(colorKey)} !default;`); } } bsColors.push('// quarto-scss-analysis-annotation { "action": "pop" }'); + const scssWithQuartoAnnotation = ( + x: string | undefined, + origin: string + ): string => { + if (!x) { + return ""; + } + + return [ + `// quarto-scss-analysis-annotation { "action": "push", "origin": "_brand.yml defaults.bootstrap.${origin}" }`, + x, + '// quarto-scss-analysis-annotation { "action": "pop" }', + ].join("\n"); + }; + return { defaults: bsColors.join("\n") + "\n" + bsVariables.join("\n"), - uses: "", - functions: "", - mixins: "", - rules: "", + uses: scssWithQuartoAnnotation(brandBootstrap.uses, "uses"), + functions: scssWithQuartoAnnotation( + brandBootstrap.functions, + "functions" + ), + mixins: scssWithQuartoAnnotation(brandBootstrap.mixins, "mixins"), + rules: scssWithQuartoAnnotation(brandBootstrap.rules, "rules"), }; };