Skip to content

Commit 2234916

Browse files
default to alternate logo; preserve light and dark brand
and enablesDarkMode flag until merging with theme, when we know whether we need dark mode a bit messy to have this extra flag, but seems the be the only correct way
1 parent 756a0b4 commit 2234916

File tree

14 files changed

+202
-44
lines changed

14 files changed

+202
-44
lines changed

src/command/render/render-contexts.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ import {
8686
import { ExtensionContext } from "../../extension/types.ts";
8787
import { NotebookContext } from "../../render/notebook/notebook-types.ts";
8888
import { safeCloneDeep } from "../../core/safe-clone-deep.ts";
89+
import { darkModeDefaultMetadata } from "../../format/html/format-html-info.ts";
8990

9091
export async function resolveFormatsFromMetadata(
9192
metadata: Metadata,
@@ -569,8 +570,16 @@ async function resolveFormats(
569570

570571
// resolve brand in project and forward it to format
571572
const brand = await project.resolveBrand(target.source);
572-
mergedFormats[format].render.brand = brand;
573-
573+
if (brand) {
574+
mergedFormats[format].render.brand = {
575+
light: brand.light,
576+
dark: (brand.enablesDarkMode ||
577+
darkModeDefaultMetadata(mergedFormats[format].metadata) !==
578+
undefined)
579+
? brand.dark
580+
: undefined,
581+
};
582+
}
574583
// apply defaults from brand yaml under the metadata of the current format
575584
const brandFormatDefaults: Metadata =
576585
(brand?.light?.data?.defaults?.quarto as unknown as Record<

src/core/brand/brand.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,12 @@ export type LightDarkBrand = {
269269
dark?: Brand;
270270
};
271271

272+
export type LightDarkBrandDarkFlag = {
273+
light?: Brand;
274+
dark?: Brand;
275+
enablesDarkMode: boolean;
276+
};
277+
272278
export type LightDarkColor = {
273279
light?: string;
274280
dark?: string;
@@ -327,8 +333,8 @@ export function resolveLogo(
327333
};
328334
if (!spec) {
329335
return {
330-
light: findLogo("light", order),
331-
dark: findLogo("dark", order),
336+
light: findLogo("light", order) || findLogo("dark", order),
337+
dark: findLogo("dark", order) || findLogo("light", order),
332338
};
333339
}
334340
if (typeof spec === "string") {
@@ -358,6 +364,15 @@ export function resolveLogo(
358364
} else {
359365
dark = resolveLogoOptions("dark", spec.dark);
360366
}
367+
// light logo default to dark logo if no light logo specified
368+
if (!light && dark) {
369+
light = { ...dark };
370+
}
371+
// dark logo default to light logo if no dark logo specified
372+
// and dark mode is enabled
373+
if (!dark && light && brand && brand.dark) {
374+
dark = { ...light };
375+
}
361376
return {
362377
light,
363378
dark,
@@ -466,7 +481,7 @@ export function splitUnifiedBrand(
466481
unified: unknown,
467482
brandDir: string,
468483
projectDir: string,
469-
): LightDarkBrand {
484+
): LightDarkBrandDarkFlag {
470485
const unifiedBrand: BrandUnified = Zod.BrandUnified.parse(unified);
471486
let typography: BrandTypographySingle | undefined = undefined;
472487
let headingsColor: LightDarkColor | undefined = undefined;
@@ -629,8 +644,7 @@ export function splitUnifiedBrand(
629644
}
630645
return {
631646
light: new Brand(lightBrand, brandDir, projectDir),
632-
dark: brandHasDarkMode(unifiedBrand)
633-
? new Brand(darkBrand, brandDir, projectDir)
634-
: undefined,
647+
dark: new Brand(darkBrand, brandDir, projectDir),
648+
enablesDarkMode: brandHasDarkMode(unifiedBrand),
635649
};
636650
}

src/format/dashboard/format-dashboard.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export function dashboardFormat() {
122122
}
123123
}
124124

125-
const brand = await project.resolveBrand(input);
125+
const brand = format.render.brand;
126126
let logoSpec = format.metadata[kLogo] as LogoLightDarkSpecifier;
127127
if (typeof logoSpec === "string" && format.metadata[kLogoAlt]) {
128128
logoSpec = {
@@ -135,7 +135,6 @@ export function dashboardFormat() {
135135
"medium",
136136
"large",
137137
]);
138-
console.log("dash logo", format.metadata[kLogo]);
139138

140139
const extras: FormatExtras = await baseHtmlFormat.formatExtras(
141140
input,

src/format/html/format-html-info.ts

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,36 +38,48 @@ export function formatDarkMode(format: Format): boolean | undefined {
3838
return undefined;
3939
}
4040

41-
export function darkModeDefault(format: Format): boolean | undefined {
42-
const metadata = format.metadata;
43-
const brand = format.render.brand;
44-
if (metadata !== undefined) {
45-
if (metadata[kTheme] && typeof metadata[kTheme] === "object") {
46-
const keys = Object.keys(metadata[kTheme]);
47-
if (keys.includes("dark")) {
48-
if (keys[0] === "dark") {
49-
return true;
50-
} else {
51-
return false;
52-
}
41+
// there are two stages of knowing whether dark mode is enabled:
42+
// 1. from the start we can look at theme and brand metadata to see if there is
43+
// a dark theme or brand
44+
// 2. later, after brand is loaded, we'll know whether unified brand enabled dark mode
45+
// in practice, we only know
46+
export function darkModeDefaultMetadata(
47+
metadata: Metadata,
48+
): boolean | undefined {
49+
if (metadata[kTheme] && typeof metadata[kTheme] === "object") {
50+
const keys = Object.keys(metadata[kTheme]);
51+
if (keys.includes("dark")) {
52+
if (keys[0] === "dark") {
53+
return true;
54+
} else {
55+
return false;
5356
}
5457
}
55-
if (metadata[kBrand] || brand) {
56-
if (metadata[kBrand] && typeof metadata[kBrand] === "object") {
57-
const keys = Object.keys(metadata[kBrand]);
58-
if (keys.includes("dark")) {
59-
if (keys[0] === "dark") {
60-
return true;
61-
} else {
62-
return false;
63-
}
64-
}
65-
}
66-
if (brand && brand.dark) {
67-
// unified brand has no author preference but it can have dark mode
58+
}
59+
if (metadata[kBrand] && typeof metadata[kBrand] === "object") {
60+
const keys = Object.keys(metadata[kBrand]);
61+
if (keys.includes("dark")) {
62+
if (keys[0] === "dark") {
63+
return true;
64+
} else {
6865
return false;
6966
}
7067
}
7168
}
7269
return undefined;
7370
}
71+
export function darkModeDefault(format: Format): boolean | undefined {
72+
const metadata = format.metadata;
73+
if (metadata !== undefined) {
74+
const dmdm = darkModeDefaultMetadata(metadata);
75+
if (dmdm !== undefined) {
76+
return dmdm;
77+
}
78+
}
79+
const brand = format.render.brand;
80+
if (brand && brand.dark) {
81+
// unified brand has no author preference but it can have dark mode
82+
return false;
83+
}
84+
return undefined;
85+
}

src/project/project-shared.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import { Zod } from "../resources/types/zod/schema-types.ts";
5151
import {
5252
Brand,
5353
LightDarkBrand,
54+
LightDarkBrandDarkFlag,
5455
splitUnifiedBrand,
5556
} from "../core/brand/brand.ts";
5657
import { assert } from "testing/asserts";
@@ -520,7 +521,7 @@ export const ensureFileInformationCache = (
520521
export async function projectResolveBrand(
521522
project: ProjectContext,
522523
fileName?: string,
523-
): Promise<{ light?: Brand; dark?: Brand } | undefined> {
524+
): Promise<LightDarkBrandDarkFlag | undefined> {
524525
async function loadSingleBrand(brandPath: string): Promise<Brand> {
525526
const brand = await readAndValidateYamlFromFile(
526527
brandPath,
@@ -529,7 +530,9 @@ export async function projectResolveBrand(
529530
);
530531
return new Brand(brand, dirname(brandPath), project.dir);
531532
}
532-
async function loadUnifiedBrand(brandPath: string): Promise<LightDarkBrand> {
533+
async function loadUnifiedBrand(
534+
brandPath: string,
535+
): Promise<LightDarkBrandDarkFlag> {
533536
const brand = await readAndValidateYamlFromFile(
534537
brandPath,
535538
refSchema("brand-unified", "Format-independent brand configuration."),
@@ -576,6 +579,7 @@ export async function projectResolveBrand(
576579
dark: brand.dark
577580
? await loadSingleBrand(resolveBrandPath(brand.dark, project.dir))
578581
: undefined,
582+
enablesDarkMode: !!brand.dark,
579583
};
580584
return project.brandCache.brand;
581585
}
@@ -631,7 +635,7 @@ export async function projectResolveBrand(
631635
project.dir,
632636
);
633637
}
634-
fileInformation.brand = { light, dark };
638+
fileInformation.brand = { light, dark, enablesDarkMode: !!dark };
635639
} else {
636640
fileInformation.brand = splitUnifiedBrand(
637641
brand,

src/project/types.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
import { RenderServices } from "../command/render/types.ts";
88
import { Metadata, PandocFlags } from "../config/types.ts";
99
import { Format, FormatExtras } from "../config/types.ts";
10-
import { Brand, LightDarkBrand } from "../core/brand/brand.ts";
10+
import {
11+
Brand,
12+
LightDarkBrand,
13+
LightDarkBrandDarkFlag,
14+
} from "../core/brand/brand.ts";
1115
import { MappedString } from "../core/mapped-text.ts";
1216
import { PartitionedMarkdown } from "../core/pandoc/types.ts";
1317
import { ExecutionEngine, ExecutionTarget } from "../execute/types.ts";
@@ -57,7 +61,7 @@ export type FileInformation = {
5761
engine?: ExecutionEngine;
5862
target?: ExecutionTarget;
5963
metadata?: Metadata;
60-
brand?: LightDarkBrand;
64+
brand?: LightDarkBrandDarkFlag;
6165
};
6266

6367
export interface ProjectContext extends Cloneable<ProjectContext> {
@@ -71,11 +75,11 @@ export interface ProjectContext extends Cloneable<ProjectContext> {
7175
fileInformationCache: Map<string, FileInformation>;
7276

7377
// This is a cache of _brand.yml for a project
74-
brandCache?: { brand?: LightDarkBrand };
78+
brandCache?: { brand?: LightDarkBrandDarkFlag };
7579
resolveBrand: (
7680
fileName?: string,
7781
) => Promise<
78-
undefined | { light?: Brand | undefined; dark?: Brand | undefined }
82+
undefined | LightDarkBrandDarkFlag
7983
>;
8084

8185
// expands markdown for a file

tests/docs/smoke-all/2024/07/09/issue-10251/index.qmd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ _quarto:
55
html:
66
ensureHtmlElements:
77
-
8-
- 'img[src="https://quarto.org/quarto.png"][alt="this is the alt text that for the logo in the sidebar"][class="sidebar-logo light-content py-0 d-lg-inline d-none"]'
9-
- 'img[src="https://quarto.org/quarto.png"][alt="this is the alt text that for the logo in the navbar"][class="navbar-logo"]'
8+
- 'img[src="https://quarto.org/quarto.png"][alt="this is the alt text that for the logo in the sidebar"][class*="sidebar-logo light-content"]'
9+
- 'img[src="https://quarto.org/quarto.png"][alt="this is the alt text that for the logo in the navbar"][class*="navbar-logo light-content"]'
1010
- []
1111
---
1212

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
logo:
2+
images:
3+
light-logo:
4+
path: light-logo.png
5+
alt: light logo
6+
dark-logo:
7+
path: dark-logo.png
8+
alt: dark logo
9+
small:
10+
light: light-logo
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
title: Yes dark logo if theme enables dark mode
3+
format:
4+
dashboard:
5+
theme:
6+
light: default
7+
dark: darkly # Explicitly enable dark mode
8+
brand: logo-light-only.yml
9+
logo:
10+
light: quarto.png
11+
_quarto:
12+
tests:
13+
dashboard:
14+
ensureHtmlElements:
15+
-
16+
- 'img[src="quarto.png"][alt=""][class="navbar-logo light-content d-inline-block"]'
17+
- 'img[src="light-logo.png"][alt="light logo"][class="navbar-logo dark-content d-inline-block"]'
18+
- []
19+
---
20+
21+
22+
There is ambiguity whether this should use `quarto.png` for the dark logo, since
23+
the brand provides no dark logos, but if that's the intention then use
24+
25+
```yaml
26+
logo: quarto.png
27+
```
28+
29+
30+
{{< lipsum 4 >}}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
title: Yes dark logo if theme enables dark mode
3+
format:
4+
dashboard:
5+
theme:
6+
light: default
7+
dark: darkly
8+
brand:
9+
logo:
10+
images:
11+
light-logo:
12+
path: light-logo.png
13+
alt: light logo
14+
small:
15+
light: light-logo
16+
logo:
17+
light: quarto.png
18+
_quarto:
19+
tests:
20+
dashboard:
21+
ensureHtmlElements:
22+
-
23+
- 'img[src="quarto.png"][alt=""][class="navbar-logo light-content d-inline-block"]'
24+
- 'img[src="light-logo.png"][alt="light logo"][class="navbar-logo dark-content d-inline-block"]'
25+
- []
26+
---
27+
28+
There is ambiguity whether this should use `quarto.png` for the dark logo, since
29+
the brand provides no dark logos, but if that's the intention then use
30+
31+
```yaml
32+
logo: quarto.png
33+
```
34+
35+
36+
{{< lipsum 4 >}}

0 commit comments

Comments
 (0)