Skip to content

Commit bbc6150

Browse files
committed
support 'brand' in theme configurations
1 parent 6676124 commit bbc6150

File tree

6 files changed

+181
-194
lines changed

6 files changed

+181
-194
lines changed

src/command/render/pandoc-html.ts

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import {
1414
kQuartoCssVariables,
1515
kTextHighlightingMode,
1616
SassBundle,
17+
SassBundleWithBrand,
18+
SassLayer,
1719
} from "../../config/types.ts";
1820
import { ProjectContext } from "../../project/types.ts";
1921

@@ -39,6 +41,8 @@ import { kSassBundles } from "../../config/types.ts";
3941
import { md5HashBytes } from "../../core/hash.ts";
4042
import { InternalError } from "../../core/lib/error.ts";
4143
import { writeTextFileSyncPreserveMode } from "../../core/write.ts";
44+
import { getStack } from "../../core/deno/debug.ts";
45+
import { assert } from "testing/asserts";
4246

4347
// The output target for a sass bundle
4448
// (controls the overall style tag that is emitted)
@@ -57,12 +61,12 @@ export async function resolveSassBundles(
5761
) {
5862
extras = cloneDeep(extras);
5963

60-
const mergedBundles: Record<string, SassBundle[]> = {};
64+
const mergedBundles: Record<string, SassBundleWithBrand[]> = {};
6165

6266
// groups the bundles by dependency name
6367
const group = (
64-
bundles: SassBundle[],
65-
groupedBundles: Record<string, SassBundle[]>,
68+
bundles: SassBundleWithBrand[],
69+
groupedBundles: Record<string, SassBundleWithBrand[]>,
6670
) => {
6771
bundles.forEach((bundle) => {
6872
if (!groupedBundles[bundle.dependency]) {
@@ -82,19 +86,37 @@ export async function resolveSassBundles(
8286
let defaultStyle: "dark" | "light" | undefined = undefined;
8387
for (const dependency of Object.keys(mergedBundles)) {
8488
// compile the cssPath
85-
const bundles = mergedBundles[dependency];
89+
const bundlesWithBrand = mergedBundles[dependency];
90+
// first, pull out the brand-specific layers
91+
//
92+
// the brand bundle itself doesn't have any 'brand' entries;
93+
// those are used to specify where the brand-specific layers should be inserted
94+
// in the final bundle. We filter
95+
const brandLayersMaybeBrand = bundlesWithBrand.find((bundle) =>
96+
bundle.key === "brand"
97+
)?.user || [];
98+
assert(!brandLayersMaybeBrand.find((v) => v === "brand"));
99+
const brandLayers = brandLayersMaybeBrand as SassLayer[];
100+
const bundles: SassBundle[] = bundlesWithBrand.filter((bundle) =>
101+
bundle.key !== "brand"
102+
).map((bundle) => {
103+
const userBrand = bundle.user?.findIndex((layer) => layer === "brand");
104+
if (userBrand && userBrand !== -1) {
105+
bundle = cloneDeep(bundle);
106+
bundle.user!.splice(userBrand, 1, ...brandLayers);
107+
}
108+
return bundle as SassBundle;
109+
});
86110

87111
// See if any bundles are providing dark specific css
88112
const hasDark = bundles.some((bundle) => bundle.dark !== undefined);
89-
defaultStyle = bundles.some((bundle) =>
90-
bundle.dark !== undefined && bundle.dark.default
91-
)
92-
? "dark"
93-
: "light";
94-
113+
defaultStyle =
114+
bundles.some((bundle) => bundle.dark !== undefined && bundle.dark.default)
115+
? "dark"
116+
: "light";
95117
const targets: SassTarget[] = [{
96118
name: `${dependency}.min.css`,
97-
bundles,
119+
bundles: (bundles as any),
98120
attribs: {
99121
"append-hash": "true",
100122
},
@@ -119,7 +141,7 @@ export async function resolveSassBundles(
119141
});
120142
targets.push({
121143
name: `${dependency}-dark.min.css`,
122-
bundles: darkBundles,
144+
bundles: darkBundles as any,
123145
attribs: {
124146
"append-hash": "true",
125147
...attribForThemeStyle("dark", defaultStyle),

src/config/types.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,28 @@ export interface SassLayer {
305305
rules: string;
306306
}
307307

308+
export interface SassBundleLayersWithBrand {
309+
key: string;
310+
user?: (SassLayer | "brand")[];
311+
quarto?: SassLayer;
312+
framework?: SassLayer;
313+
loadPaths?: string[];
314+
}
315+
316+
export interface SassBundleWithBrand extends SassBundleLayersWithBrand {
317+
dependency: string;
318+
dark?: {
319+
user?: (SassLayer | "brand")[];
320+
quarto?: SassLayer;
321+
framework?: SassLayer;
322+
default?: boolean;
323+
};
324+
attribs?: Record<string, string>;
325+
}
326+
308327
export interface SassBundleLayers {
309328
key: string;
310-
user?: SassLayer;
329+
user?: SassLayer[];
311330
quarto?: SassLayer;
312331
framework?: SassLayer;
313332
loadPaths?: string[];
@@ -316,7 +335,7 @@ export interface SassBundleLayers {
316335
export interface SassBundle extends SassBundleLayers {
317336
dependency: string;
318337
dark?: {
319-
user?: SassLayer;
338+
user?: SassLayer[];
320339
quarto?: SassLayer;
321340
framework?: SassLayer;
322341
default?: boolean;
@@ -376,7 +395,7 @@ export interface FormatExtras {
376395
templateContext?: FormatTemplateContext;
377396
html?: {
378397
[kDependencies]?: FormatDependency[];
379-
[kSassBundles]?: SassBundle[];
398+
[kSassBundles]?: SassBundleWithBrand[];
380399
[kBodyEnvelope]?: BodyEnvelope;
381400
[kHtmlPostprocessors]?: Array<HtmlPostProcessor>;
382401
[kHtmlFinalizers]?: Array<

src/core/sass.ts

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,19 @@ export async function compileSass(
8181
);
8282
const quartoDefaults = bundles.map((bundle) => bundle.quarto?.defaults || "");
8383
const quartoRules = bundles.map((bundle) => bundle.quarto?.rules || "");
84-
8584
const quartoMixins = bundles.map((bundle) => bundle.quarto?.mixins || "");
8685

86+
const userLayers = mergeLayers(
87+
...bundles.map((bundle) => bundle.user || []).flat(),
88+
);
89+
console.log("userLayers", userLayers);
90+
8791
// Gather sasslayer for the user
88-
const userUses = bundles.map((bundle) => bundle.user?.uses || "");
89-
const userFunctions = bundles.map((bundle) => bundle.user?.functions || "");
90-
const userDefaults = bundles.map((bundle) => bundle.user?.defaults || "");
91-
const userRules = bundles.map((bundle) => bundle.user?.rules || "");
92-
const userMixins = bundles.map((bundle) => bundle.user?.mixins || "");
92+
const userUses = userLayers.uses; //bundles.map((bundle) => bundle.user?.uses || "");
93+
const userFunctions = userLayers.functions; // bundles.map((bundle) => bundle.user?.functions || "");
94+
const userDefaults = userLayers.defaults; // bundles.map((bundle) => bundle.user?.defaults || "");
95+
const userRules = userLayers.rules; // bundles.map((bundle) => bundle.user?.rules || "");
96+
const userMixins = userLayers.mixins; // bundles.map((bundle) => bundle.user?.mixins || "");
9397

9498
// Set any load paths used to resolve imports
9599
const loadPaths: string[] = [];
@@ -114,15 +118,15 @@ export async function compileSass(
114118
'// quarto-scss-analysis-annotation { "origin": "\'use\' section from Quarto" }',
115119
...quartoUses,
116120
'// quarto-scss-analysis-annotation { "origin": "\'use\' section from user-defined SCSS" }',
117-
...userUses,
121+
userUses,
118122
'// quarto-scss-analysis-annotation { "origin": "\'functions\' section from format" }',
119123
...frameworkFunctions,
120124
'// quarto-scss-analysis-annotation { "origin": "\'functions\' section from Quarto" }',
121125
...quartoFunctions,
122126
'// quarto-scss-analysis-annotation { "origin": "\'functions\' section from user-defined SCSS" }',
123-
...userFunctions,
127+
userFunctions,
124128
'// quarto-scss-analysis-annotation { "origin": "Defaults from user-defined SCSS" }',
125-
...userDefaults.reverse(),
129+
userDefaults,
126130
'// quarto-scss-analysis-annotation { "origin": "Defaults from Quarto\'s SCSS" }',
127131
...quartoDefaults.reverse(),
128132
'// quarto-scss-analysis-annotation { "origin": "Defaults from the format SCSS" }',
@@ -138,7 +142,7 @@ export async function compileSass(
138142
'// quarto-scss-analysis-annotation { "origin": "\'rules\' section from Quarto" }',
139143
...quartoRules,
140144
'// quarto-scss-analysis-annotation { "origin": "\'rules\' section from user-defined SCSS" }',
141-
...userRules,
145+
userRules,
142146
'// quarto-scss-analysis-annotation { "origin": null }',
143147
].join("\n\n");
144148

@@ -191,7 +195,7 @@ const layoutBoundary =
191195
const kLayerBoundaryLine = RegExp(layoutBoundary);
192196
const kLayerBoundaryTest = RegExp(layoutBoundary, "m");
193197

194-
export function mergeLayers(...layers: SassLayer[]) {
198+
export function mergeLayers(...layers: SassLayer[]): SassLayer {
195199
const themeUses: string[] = [];
196200
const themeDefaults: string[] = [];
197201
const themeRules: string[] = [];
@@ -202,10 +206,7 @@ export function mergeLayers(...layers: SassLayer[]) {
202206
themeUses.push(theme.uses);
203207
}
204208
if (theme.defaults) {
205-
// We need to reverse the order of defaults
206-
// since defaults override one another by being
207-
// set first
208-
themeDefaults.unshift(theme.defaults);
209+
themeDefaults.push(theme.defaults);
209210
}
210211

211212
if (theme.rules) {
@@ -223,7 +224,10 @@ export function mergeLayers(...layers: SassLayer[]) {
223224

224225
return {
225226
uses: themeUses.join("\n"),
226-
defaults: themeDefaults.join("\n"),
227+
// We need to reverse the order of defaults
228+
// since defaults override one another by being
229+
// set first
230+
defaults: themeDefaults.reverse().join("\n"),
227231
functions: themeFunctions.join("\n"),
228232
mixins: themeMixins.join("\n"),
229233
rules: themeRules.join("\n"),

0 commit comments

Comments
 (0)