diff --git a/src/command/render/pandoc-html.ts b/src/command/render/pandoc-html.ts
index e0612e7800d..758c2546e7e 100644
--- a/src/command/render/pandoc-html.ts
+++ b/src/command/render/pandoc-html.ts
@@ -14,6 +14,8 @@ import {
kQuartoCssVariables,
kTextHighlightingMode,
SassBundle,
+ SassBundleWithBrand,
+ SassLayer,
} from "../../config/types.ts";
import { ProjectContext } from "../../project/types.ts";
@@ -39,6 +41,7 @@ import { kSassBundles } from "../../config/types.ts";
import { md5HashBytes } from "../../core/hash.ts";
import { InternalError } from "../../core/lib/error.ts";
import { writeTextFileSyncPreserveMode } from "../../core/write.ts";
+import { assert } from "testing/asserts";
// The output target for a sass bundle
// (controls the overall style tag that is emitted)
@@ -57,12 +60,12 @@ export async function resolveSassBundles(
) {
extras = cloneDeep(extras);
- const mergedBundles: Record = {};
+ const mergedBundles: Record = {};
// groups the bundles by dependency name
const group = (
- bundles: SassBundle[],
- groupedBundles: Record,
+ bundles: SassBundleWithBrand[],
+ groupedBundles: Record,
) => {
bundles.forEach((bundle) => {
if (!groupedBundles[bundle.dependency]) {
@@ -82,19 +85,37 @@ export async function resolveSassBundles(
let defaultStyle: "dark" | "light" | undefined = undefined;
for (const dependency of Object.keys(mergedBundles)) {
// compile the cssPath
- const bundles = mergedBundles[dependency];
+ const bundlesWithBrand = mergedBundles[dependency];
+ // first, pull out the brand-specific layers
+ //
+ // the brand bundle itself doesn't have any 'brand' entries;
+ // those are used to specify where the brand-specific layers should be inserted
+ // in the final bundle. We filter
+ const brandLayersMaybeBrand = bundlesWithBrand.find((bundle) =>
+ bundle.key === "brand"
+ )?.user || [];
+ assert(!brandLayersMaybeBrand.find((v) => v === "brand"));
+ const brandLayers = brandLayersMaybeBrand as SassLayer[];
+ const bundles: SassBundle[] = bundlesWithBrand.filter((bundle) =>
+ bundle.key !== "brand"
+ ).map((bundle) => {
+ const userBrand = bundle.user?.findIndex((layer) => layer === "brand");
+ if (userBrand && userBrand !== -1) {
+ bundle = cloneDeep(bundle);
+ bundle.user!.splice(userBrand, 1, ...brandLayers);
+ }
+ return bundle as SassBundle;
+ });
// See if any bundles are providing dark specific css
const hasDark = bundles.some((bundle) => bundle.dark !== undefined);
- defaultStyle = bundles.some((bundle) =>
- bundle.dark !== undefined && bundle.dark.default
- )
- ? "dark"
- : "light";
-
+ defaultStyle =
+ bundles.some((bundle) => bundle.dark !== undefined && bundle.dark.default)
+ ? "dark"
+ : "light";
const targets: SassTarget[] = [{
name: `${dependency}.min.css`,
- bundles,
+ bundles: (bundles as any),
attribs: {
"append-hash": "true",
},
@@ -119,7 +140,7 @@ export async function resolveSassBundles(
});
targets.push({
name: `${dependency}-dark.min.css`,
- bundles: darkBundles,
+ bundles: darkBundles as any,
attribs: {
"append-hash": "true",
...attribForThemeStyle("dark", defaultStyle),
@@ -141,6 +162,9 @@ export async function resolveSassBundles(
// it can happen that processing generate an empty css file (e.g quarto-html deps with Quarto CSS variables)
// in that case, no need to insert the cssPath in the dependency
if (!cssPath) continue;
+ if (Deno.readTextFileSync(cssPath).length === 0) {
+ continue;
+ }
// Process attributes (forward on to the target)
for (const bundle of target.bundles) {
diff --git a/src/config/types.ts b/src/config/types.ts
index 309b9878378..b7ade818fb3 100644
--- a/src/config/types.ts
+++ b/src/config/types.ts
@@ -305,9 +305,28 @@ export interface SassLayer {
rules: string;
}
+export interface SassBundleLayersWithBrand {
+ key: string;
+ user?: (SassLayer | "brand")[];
+ quarto?: SassLayer;
+ framework?: SassLayer;
+ loadPaths?: string[];
+}
+
+export interface SassBundleWithBrand extends SassBundleLayersWithBrand {
+ dependency: string;
+ dark?: {
+ user?: (SassLayer | "brand")[];
+ quarto?: SassLayer;
+ framework?: SassLayer;
+ default?: boolean;
+ };
+ attribs?: Record;
+}
+
export interface SassBundleLayers {
key: string;
- user?: SassLayer;
+ user?: SassLayer[];
quarto?: SassLayer;
framework?: SassLayer;
loadPaths?: string[];
@@ -316,7 +335,7 @@ export interface SassBundleLayers {
export interface SassBundle extends SassBundleLayers {
dependency: string;
dark?: {
- user?: SassLayer;
+ user?: SassLayer[];
quarto?: SassLayer;
framework?: SassLayer;
default?: boolean;
@@ -376,7 +395,7 @@ export interface FormatExtras {
templateContext?: FormatTemplateContext;
html?: {
[kDependencies]?: FormatDependency[];
- [kSassBundles]?: SassBundle[];
+ [kSassBundles]?: SassBundleWithBrand[];
[kBodyEnvelope]?: BodyEnvelope;
[kHtmlPostprocessors]?: Array;
[kHtmlFinalizers]?: Array<
diff --git a/src/core/sass.ts b/src/core/sass.ts
index 5adfeef0077..a5aa41a5e5d 100644
--- a/src/core/sass.ts
+++ b/src/core/sass.ts
@@ -81,15 +81,18 @@ export async function compileSass(
);
const quartoDefaults = bundles.map((bundle) => bundle.quarto?.defaults || "");
const quartoRules = bundles.map((bundle) => bundle.quarto?.rules || "");
-
const quartoMixins = bundles.map((bundle) => bundle.quarto?.mixins || "");
+ const userLayers = mergeLayers(
+ ...bundles.map((bundle) => bundle.user || []).flat(),
+ );
+
// Gather sasslayer for the user
- const userUses = bundles.map((bundle) => bundle.user?.uses || "");
- const userFunctions = bundles.map((bundle) => bundle.user?.functions || "");
- const userDefaults = bundles.map((bundle) => bundle.user?.defaults || "");
- const userRules = bundles.map((bundle) => bundle.user?.rules || "");
- const userMixins = bundles.map((bundle) => bundle.user?.mixins || "");
+ const userUses = userLayers.uses; //bundles.map((bundle) => bundle.user?.uses || "");
+ const userFunctions = userLayers.functions; // bundles.map((bundle) => bundle.user?.functions || "");
+ const userDefaults = userLayers.defaults; // bundles.map((bundle) => bundle.user?.defaults || "");
+ const userRules = userLayers.rules; // bundles.map((bundle) => bundle.user?.rules || "");
+ const userMixins = userLayers.mixins; // bundles.map((bundle) => bundle.user?.mixins || "");
// Set any load paths used to resolve imports
const loadPaths: string[] = [];
@@ -114,15 +117,15 @@ export async function compileSass(
'// quarto-scss-analysis-annotation { "origin": "\'use\' section from Quarto" }',
...quartoUses,
'// quarto-scss-analysis-annotation { "origin": "\'use\' section from user-defined SCSS" }',
- ...userUses,
+ userUses,
'// quarto-scss-analysis-annotation { "origin": "\'functions\' section from format" }',
...frameworkFunctions,
'// quarto-scss-analysis-annotation { "origin": "\'functions\' section from Quarto" }',
...quartoFunctions,
'// quarto-scss-analysis-annotation { "origin": "\'functions\' section from user-defined SCSS" }',
- ...userFunctions,
+ userFunctions,
'// quarto-scss-analysis-annotation { "origin": "Defaults from user-defined SCSS" }',
- ...userDefaults.reverse(),
+ userDefaults,
'// quarto-scss-analysis-annotation { "origin": "Defaults from Quarto\'s SCSS" }',
...quartoDefaults.reverse(),
'// quarto-scss-analysis-annotation { "origin": "Defaults from the format SCSS" }',
@@ -132,13 +135,13 @@ export async function compileSass(
'// quarto-scss-analysis-annotation { "origin": "\'mixins\' section from Quarto" }',
...quartoMixins,
'// quarto-scss-analysis-annotation { "origin": "\'mixins\' section from user-defined SCSS" }',
- ...userMixins,
+ userMixins,
'// quarto-scss-analysis-annotation { "origin": "\'rules\' section from format" }',
...frameworkRules,
'// quarto-scss-analysis-annotation { "origin": "\'rules\' section from Quarto" }',
...quartoRules,
'// quarto-scss-analysis-annotation { "origin": "\'rules\' section from user-defined SCSS" }',
- ...userRules,
+ userRules,
'// quarto-scss-analysis-annotation { "origin": null }',
].join("\n\n");
@@ -191,7 +194,7 @@ const layoutBoundary =
const kLayerBoundaryLine = RegExp(layoutBoundary);
const kLayerBoundaryTest = RegExp(layoutBoundary, "m");
-export function mergeLayers(...layers: SassLayer[]) {
+export function mergeLayers(...layers: SassLayer[]): SassLayer {
const themeUses: string[] = [];
const themeDefaults: string[] = [];
const themeRules: string[] = [];
@@ -202,10 +205,7 @@ export function mergeLayers(...layers: SassLayer[]) {
themeUses.push(theme.uses);
}
if (theme.defaults) {
- // We need to reverse the order of defaults
- // since defaults override one another by being
- // set first
- themeDefaults.unshift(theme.defaults);
+ themeDefaults.push(theme.defaults);
}
if (theme.rules) {
@@ -223,7 +223,10 @@ export function mergeLayers(...layers: SassLayer[]) {
return {
uses: themeUses.join("\n"),
- defaults: themeDefaults.join("\n"),
+ // We need to reverse the order of defaults
+ // since defaults override one another by being
+ // set first
+ defaults: themeDefaults.reverse().join("\n"),
functions: themeFunctions.join("\n"),
mixins: themeMixins.join("\n"),
rules: themeRules.join("\n"),
@@ -419,5 +422,5 @@ export function cleanSourceMappingUrl(cssPath: string): void {
kSourceMappingRegexes[1],
"",
);
- writeTextFileSyncPreserveMode(cssPath, cleaned);
+ writeTextFileSyncPreserveMode(cssPath, cleaned.trim());
}
diff --git a/src/core/sass/brand.ts b/src/core/sass/brand.ts
index 85691fc99ca..480957b11ed 100644
--- a/src/core/sass/brand.ts
+++ b/src/core/sass/brand.ts
@@ -11,9 +11,8 @@ import {
FormatExtras,
kSassBundles,
SassBundle,
- SassBundleLayers,
+ SassLayer,
} from "../../config/types.ts";
-import { join, relative } from "../../deno_ral/path.ts";
import { ProjectContext } from "../../project/types.ts";
import {
BrandFont,
@@ -25,6 +24,7 @@ import {
import { Brand } from "../brand/brand.ts";
const defaultColorNameMap: Record = {
+ "link-color": "link",
"pre-color": "foreground",
"body-bg": "background",
"body-color": "foreground",
@@ -67,50 +67,18 @@ export async function brandBootstrapSassBundles(
project: ProjectContext,
key: string,
): Promise {
- return (await brandBootstrapSassBundleLayers(
+ const layers = await brandBootstrapSassLayers(
fileName,
project,
- key,
defaultColorNameMap,
- )).map(
- (layer: SassBundleLayers) => {
- return {
- ...layer,
- dependency: "bootstrap",
- };
- },
);
+ return [{
+ key,
+ dependency: "bootstrap",
+ user: layers,
+ }];
}
-const fontFileFormat = (file: string): string => {
- const fragments = file.split(".");
- if (fragments.length < 2) {
- throw new Error(`Invalid font file ${file}; expected extension.`);
- }
- const ext = fragments.pop();
- // https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src#font_formats
- switch (ext) {
- case "otc":
- case "ttc":
- return "collection";
- case "woff":
- return "woff";
- case "woff2":
- return "woff2";
- case "ttf":
- return "truetype";
- case "otf":
- return "opentype";
- case "svg":
- case "svgz":
- return "svg";
- case "eot":
- return "embedded-opentype";
- default:
- throw new Error(`Unknown font format ${ext} in ${file}`);
- }
-};
-
const bunnyFontImportString = (description: BrandFontCommon) => {
const bunnyName = (name: string) => name.replace(/ /g, "-");
const bunnyFamily = description.family;
@@ -175,11 +143,10 @@ const googleFontImportString = (description: BrandFontGoogle) => {
}:${styleString}wght@${weights}&display=${display}');`;
};
-const brandColorBundle = (
+const brandColorLayer = (
brand: Brand,
- key: string,
nameMap: Record,
-): SassBundleLayers => {
+): SassLayer => {
const colorVariables: string[] = [
"/* color variables from _brand.yml */",
'// quarto-scss-analysis-annotation { "action": "push", "origin": "_brand.yml color" }',
@@ -226,24 +193,18 @@ const brandColorBundle = (
"}",
'// quarto-scss-analysis-annotation { "action": "pop" }',
);
- const colorBundle: SassBundleLayers = {
- key,
- // dependency: "bootstrap",
- quarto: {
- defaults: colorVariables.join("\n"),
- uses: "",
- functions: "",
- mixins: "",
- rules: colorCssVariables.join("\n"),
- },
+ return {
+ defaults: colorVariables.join("\n"),
+ uses: "",
+ functions: "",
+ mixins: "",
+ rules: colorCssVariables.join("\n"),
};
- return colorBundle;
};
-const brandBootstrapBundle = (
+const brandDefaultsBootstrapLayer = (
brand: Brand,
- key: string,
-): SassBundleLayers => {
+): SassLayer => {
// Bootstrap Variables from brand.defaults.bootstrap
const brandBootstrap = brand?.data?.defaults?.bootstrap as unknown as Record<
string,
@@ -300,24 +261,18 @@ const brandBootstrapBundle = (
bsColors.push('// quarto-scss-analysis-annotation { "action": "pop" }');
- const bsBundle: SassBundleLayers = {
- key,
- // dependency: "bootstrap",
- quarto: {
- defaults: bsColors.join("\n") + "\n" + bsVariables.join("\n"),
- uses: "",
- functions: "",
- mixins: "",
- rules: "",
- },
+ return {
+ defaults: bsColors.join("\n") + "\n" + bsVariables.join("\n"),
+ uses: "",
+ functions: "",
+ mixins: "",
+ rules: "",
};
- return bsBundle;
};
-const brandTypographyBundle = (
+const brandTypographyLayer = (
brand: Brand,
- key: string,
-): SassBundleLayers => {
+): SassLayer => {
const typographyVariables: string[] = [
"/* typography variables from _brand.yml */",
'// quarto-scss-analysis-annotation { "action": "push", "origin": "_brand.yml typography" }',
@@ -325,18 +280,6 @@ const brandTypographyBundle = (
const typographyImports: Set = new Set();
const fonts = brand.data?.typography?.fonts ?? [];
- const pathCorrection = relative(brand.projectDir, brand.brandDir);
- const computePath = (file: string) => {
- if (file.startsWith("http://") || file.startsWith("https://")) {
- return file;
- }
- // paths in our CSS are always relative to the project directory
- if (file.startsWith("/")) {
- return file.slice(1);
- }
- return join(pathCorrection, file);
- };
-
const getFontFamilies = (family: string | undefined) => {
return fonts.filter((font) =>
typeof font !== "string" && font.family === family
@@ -579,75 +522,61 @@ const brandTypographyBundle = (
typographyVariables.push(
'// quarto-scss-analysis-annotation { "action": "pop" }',
);
- const typographyBundle: SassBundleLayers = {
- key,
- // dependency: "bootstrap",
- quarto: {
- defaults: typographyVariables.join("\n"),
- uses: Array.from(typographyImports).join("\n"),
- functions: "",
- mixins: "",
- rules: "",
- },
+ return {
+ defaults: typographyVariables.join("\n"),
+ uses: Array.from(typographyImports).join("\n"),
+ functions: "",
+ mixins: "",
+ rules: "",
};
- return typographyBundle;
};
-export async function brandSassBundleLayers(
+export async function brandSassLayers(
fileName: string | undefined,
project: ProjectContext,
- key: string,
nameMap: Record = {},
-): Promise {
+): Promise {
const brand = await project.resolveBrand(fileName);
- const sassBundles: SassBundleLayers[] = [];
+ const sassLayers: SassLayer[] = [];
if (brand?.data.color) {
- sassBundles.push(brandColorBundle(brand, key, nameMap));
+ sassLayers.push(brandColorLayer(brand, nameMap));
}
if (brand?.data.typography) {
- sassBundles.push(brandTypographyBundle(brand, key));
+ sassLayers.push(brandTypographyLayer(brand));
}
- return sassBundles;
+ return sassLayers;
}
-export async function brandBootstrapSassBundleLayers(
+export async function brandBootstrapSassLayers(
fileName: string | undefined,
project: ProjectContext,
- key: string,
nameMap: Record = {},
-): Promise {
- const brand = await project.resolveBrand(fileName);
- const sassBundles = await brandSassBundleLayers(
+): Promise {
+ const layers = await brandSassLayers(
fileName,
project,
- key,
nameMap,
);
+ const brand = await project.resolveBrand(fileName);
if (brand?.data?.defaults?.bootstrap) {
- const bsBundle = brandBootstrapBundle(brand, key);
- if (bsBundle) {
- // Add bsBundle to the beginning of the array so that defaults appear
- // *after* the rest of the brand variables.
- sassBundles.unshift(bsBundle);
- }
+ layers.push(brandDefaultsBootstrapLayer(brand));
}
- return sassBundles;
+ return layers;
}
-export async function brandRevealSassBundleLayers(
+export async function brandRevealSassLayers(
input: string | undefined,
_format: Format,
project: ProjectContext,
-): Promise {
- return brandSassBundleLayers(
+): Promise {
+ return brandSassLayers(
input,
project,
- "reveal-theme",
defaultColorNameMap,
);
}
@@ -657,25 +586,20 @@ export async function brandSassFormatExtras(
_format: Format,
project: ProjectContext,
): Promise {
- const htmlSassBundleLayers = await brandBootstrapSassBundleLayers(
+ const htmlSassBundleLayers = await brandBootstrapSassLayers(
input,
project,
- "brand",
defaultColorNameMap,
);
- const htmlSassBundles: SassBundle[] = htmlSassBundleLayers.map((layer) => {
- return {
- ...layer,
- dependency: "bootstrap",
- };
- });
- if (htmlSassBundles.length === 0) {
- return {};
- } else {
- return {
- html: {
- [kSassBundles]: htmlSassBundles,
- },
- };
- }
+ return {
+ html: {
+ [kSassBundles]: [
+ {
+ key: "brand",
+ dependency: "bootstrap",
+ user: htmlSassBundleLayers,
+ },
+ ],
+ },
+ };
}
diff --git a/src/format/html/format-html-scss.ts b/src/format/html/format-html-scss.ts
index b355249c6d9..5516df9fd3c 100644
--- a/src/format/html/format-html-scss.ts
+++ b/src/format/html/format-html-scss.ts
@@ -19,7 +19,12 @@ import { mergeLayers, sassLayer } from "../../core/sass.ts";
import { outputVariable, SassVariable, sassVariable } from "../../core/sass.ts";
-import { Format, SassBundle, SassLayer } from "../../config/types.ts";
+import {
+ Format,
+ SassBundle,
+ SassBundleWithBrand,
+ SassLayer,
+} from "../../config/types.ts";
import { Metadata } from "../../config/types.ts";
import { kGrid, kTheme } from "../../config/constants.ts";
@@ -56,6 +61,7 @@ import {
sassUtilFunctions,
} from "./format-html-shared.ts";
import { readHighlightingTheme } from "../../quarto-core/text-highlighting.ts";
+import { warn } from "log";
export interface Themes {
light: string[];
@@ -65,12 +71,12 @@ export interface Themes {
function layerQuartoScss(
key: string,
dependency: string,
- sassLayer: SassLayer,
+ sassLayer: (SassLayer | "brand")[],
format: Format,
- darkLayer?: SassLayer,
+ darkLayer?: (SassLayer | "brand")[],
darkDefault?: boolean,
loadPaths?: string[],
-): SassBundle {
+): SassBundleWithBrand {
// Compose the base Quarto SCSS
const uses = quartoUses();
const defaults = [
@@ -155,7 +161,7 @@ export function resolveBootstrapScss(
input: string,
format: Format,
sassLayers: SassLayer[],
-): SassBundle[] {
+): SassBundleWithBrand[] {
// Quarto built in css
const quartoThemesDir = formatResourcePath(
"html",
@@ -173,7 +179,7 @@ export function resolveBootstrapScss(
);
// Find light and dark sass layers
- const sassBundles: SassBundle[] = [];
+ const sassBundles: SassBundleWithBrand[] = [];
// light
sassBundles.push(
@@ -192,27 +198,33 @@ export function resolveBootstrapScss(
}
export interface ThemeSassLayer {
- light: SassLayer;
- dark?: SassLayer;
+ light: (SassLayer | "brand")[];
+ dark?: (SassLayer | "brand")[];
}
function layerTheme(
input: string,
themes: string[],
quartoThemesDir: string,
-): { layers: SassLayer[]; loadPaths: string[] } {
+): { layers: (SassLayer | "brand")[]; loadPaths: string[] } {
let injectedCustomization = false;
const loadPaths: string[] = [];
const layers = themes.flatMap((theme) => {
const isAbs = isAbsolute(theme);
const isScssFile = [".scss", ".css"].includes(extname(theme));
- if (isAbs && isScssFile) {
+ if (theme === "brand") {
+ // provide a brand order marker for downstream
+ // processing to know where to insert the brand scss
+ return "brand";
+ } else if (isAbs && isScssFile) {
// Absolute path to a SCSS file
if (existsSync(theme)) {
const themeDir = dirname(theme);
loadPaths.push(themeDir);
return sassLayer(theme);
+ } else {
+ warn(`Theme file not found: ${theme}`);
}
} else if (isScssFile) {
// Relative path to a SCSS file
@@ -221,6 +233,8 @@ function layerTheme(
const themeDir = dirname(themePath);
loadPaths.push(themeDir);
return sassLayer(themePath);
+ } else {
+ warn(`Theme file not found: ${themePath}`);
}
} else {
// The directory for this theme
@@ -429,10 +443,8 @@ function resolveThemeLayer(
}
const themeSassLayer = {
- light: mergeLayers(...lightLayerContext.layers),
- dark: darkLayerContext?.layers
- ? mergeLayers(...darkLayerContext?.layers)
- : undefined,
+ light: lightLayerContext.layers,
+ dark: darkLayerContext?.layers,
};
const loadPaths = [
diff --git a/src/format/reveal/format-reveal-theme.ts b/src/format/reveal/format-reveal-theme.ts
index 2b1b6fcd21c..b4e12f25844 100644
--- a/src/format/reveal/format-reveal-theme.ts
+++ b/src/format/reveal/format-reveal-theme.ts
@@ -13,6 +13,7 @@ import {
kTextHighlightingMode,
Metadata,
SassBundleLayers,
+ SassBundleLayersWithBrand,
SassLayer,
} from "../../config/types.ts";
@@ -40,7 +41,7 @@ import { asCssFont, asCssNumber } from "../../core/css.ts";
import { cssHasDarkModeSentinel } from "../../core/pandoc/css.ts";
import { pandocNativeStr } from "../../core/pandoc/codegen.ts";
import { ProjectContext } from "../../project/types.ts";
-import { brandRevealSassBundleLayers } from "../../core/sass/brand.ts";
+import { brandRevealSassLayers } from "../../core/sass/brand.ts";
import { md5HashBytes } from "../../core/hash.ts";
export const kRevealLightThemes = [
@@ -108,18 +109,28 @@ export async function revealTheme(
join(cssThemeDir, "template"),
];
+ const brandLayers: SassLayer[] = await brandRevealSassLayers(
+ input,
+ format,
+ project,
+ );
+
// theme is either user provided scss or something in our 'themes' dir
// (note that standard reveal scss themes must be converted to quarto
// theme format so they can participate in the pipeline)
const themeConfig =
(format.metadata?.[kTheme] as string | string[] | undefined) || "default";
+ let usedBrandLayers = false;
const themeLayers = (Array.isArray(themeConfig) ? themeConfig : [themeConfig])
.map(
(theme) => {
const themePath = join(relative(Deno.cwd(), dirname(input)), theme);
- if (existsSync(themePath)) {
+ if (themePath === "brand") {
+ usedBrandLayers = true;
+ return brandLayers;
+ } else if (existsSync(themePath)) {
loadPaths.unshift(join(dirname(input), dirname(theme)));
- return themeLayer(themePath);
+ return [themeLayer(themePath)];
} else {
// alias revealjs theme names
if (theme === "white") {
@@ -132,11 +143,13 @@ export async function revealTheme(
"revealjs",
join("themes", `${theme}.scss`),
);
- return themeLayer(theme);
+ return [themeLayer(theme)];
}
},
- );
-
+ ).flat();
+ if (!usedBrandLayers) {
+ themeLayers.unshift(...brandLayers);
+ }
// get any variables defined in yaml
const yamlLayer: SassLayer = {
uses: "",
@@ -174,7 +187,7 @@ export async function revealTheme(
// create sass bundle layers
const bundleLayers: SassBundleLayers = {
key: "reveal-theme",
- user: mergeLayers(...userLayers),
+ user: userLayers,
quarto: mergeLayers(
...quartoLayers,
),
@@ -182,14 +195,8 @@ export async function revealTheme(
loadPaths,
};
- const brandLayers: SassBundleLayers[] = await brandRevealSassBundleLayers(
- input,
- format,
- project,
- );
-
// compile sass
- const css = await compileSass([bundleLayers, ...brandLayers], temp);
+ const css = await compileSass([bundleLayers], temp);
// Remove sourcemap information
cleanSourceMappingUrl(css);
// convert from string to bytes
diff --git a/tests/docs/smoke-all/2022/10/14/invalid-highlight-theme.qmd b/tests/docs/smoke-all/2022/10/14/invalid-highlight-theme.qmd
index 033588b7152..66b126ef581 100644
--- a/tests/docs/smoke-all/2022/10/14/invalid-highlight-theme.qmd
+++ b/tests/docs/smoke-all/2022/10/14/invalid-highlight-theme.qmd
@@ -8,7 +8,10 @@ format:
# code-fold: true
# code-line-numbers: true
highlight-style: asa
-
+_quarto:
+ tests:
+ html:
+ noErrors: true
---
```r