Skip to content

Commit fadcf71

Browse files
dark logo: sidebar and navbar
rename functions unified -> having dark use Zod to reify enumerations unified and simple brand logo brand metadata now only contains one polarity of logo since we split the unified logo immediately unfortunate consequence of dark sidebar logo: the dreaded !important css bootstrap started it normalize and resolve all document- and project- provided logos to LightDarkLogo
1 parent 3c867fa commit fadcf71

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+654
-140
lines changed

src/core/brand/brand.ts

Lines changed: 119 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -10,57 +10,36 @@ import {
1010
BrandColorLightDark,
1111
BrandFont,
1212
BrandLogoExplicitResource,
13+
BrandLogoSingle,
14+
BrandLogoUnified,
15+
BrandNamedLogo,
1316
BrandNamedThemeColor,
1417
BrandSingle,
18+
BrandStringLightDark,
1519
BrandTypographyOptionsBase,
1620
BrandTypographyOptionsHeadingsSingle,
1721
BrandTypographySingle,
1822
BrandTypographyUnified,
1923
BrandUnified,
24+
LogoLightDarkSpecifier,
25+
LogoOptions,
26+
NormalizedLogoLightDarkSpecifier,
2027
Zod,
2128
} from "../../resources/types/zod/schema-types.ts";
2229
import { InternalError } from "../lib/error.ts";
2330

2431
import { join, relative } from "../../deno_ral/path.ts";
2532
import { warnOnce } from "../log.ts";
2633
import { isCssColorName } from "../css/color-names.ts";
27-
28-
// we can't programmatically convert typescript types to string arrays,
29-
// so we have to define this manually. They should match `BrandNamedThemeColor` in schema-types.ts
30-
31-
export const defaultColorNames: BrandNamedThemeColor[] = [
32-
"foreground",
33-
"background",
34-
"primary",
35-
"secondary",
36-
"tertiary",
37-
"success",
38-
"info",
39-
"warning",
40-
"danger",
41-
"light",
42-
"dark",
43-
"link",
44-
];
45-
46-
const defaultLogoNames: string[] = [
47-
"small",
48-
"medium",
49-
"large",
50-
];
51-
52-
type CanonicalLogoInfo = {
53-
light: BrandLogoExplicitResource;
54-
dark: BrandLogoExplicitResource;
55-
};
34+
import { assert } from "testing/asserts";
5635

5736
type ProcessedBrandData = {
5837
color: Record<string, string>;
5938
typography: BrandTypographySingle;
6039
logo: {
61-
small?: CanonicalLogoInfo;
62-
medium?: CanonicalLogoInfo;
63-
large?: CanonicalLogoInfo;
40+
small?: BrandLogoExplicitResource;
41+
medium?: BrandLogoExplicitResource;
42+
large?: BrandLogoExplicitResource;
6443
images: Record<string, BrandLogoExplicitResource>;
6544
};
6645
};
@@ -156,11 +135,7 @@ export class Brand {
156135

157136
const logo: ProcessedBrandData["logo"] = { images: {} };
158137
for (
159-
const size of [
160-
"small",
161-
"medium",
162-
"large",
163-
] as ("small" | "medium" | "large")[]
138+
const size of Zod.BrandNamedLogo.options
164139
) {
165140
const v = this.getLogo(size);
166141
if (v) {
@@ -203,7 +178,9 @@ export class Brand {
203178
if (this.data.color?.palette?.[name]) {
204179
name = this.data.color.palette[name] as string;
205180
} else if (
206-
defaultColorNames.includes(name as BrandNamedThemeColor) &&
181+
Zod.BrandNamedThemeColor.options.includes(
182+
name as BrandNamedThemeColor,
183+
) &&
207184
this.data.color?.[name as BrandNamedThemeColor]
208185
) {
209186
name = this.data.color[name as BrandNamedThemeColor]!;
@@ -278,30 +255,12 @@ export class Brand {
278255
};
279256
}
280257

281-
getLogo(name: "small" | "medium" | "large"): CanonicalLogoInfo | undefined {
258+
getLogo(name: BrandNamedLogo): BrandLogoExplicitResource | undefined {
282259
const entry = this.data.logo?.[name];
283260
if (!entry) {
284261
return undefined;
285262
}
286-
if (typeof entry === "string") {
287-
const res = this.getLogoResource(entry);
288-
return {
289-
light: res,
290-
dark: res,
291-
};
292-
}
293-
const lightEntry = entry?.light
294-
? this.getLogoResource(entry.light)
295-
: undefined;
296-
const darkEntry = entry?.dark
297-
? this.getLogoResource(entry.dark)
298-
: undefined;
299-
if (lightEntry && darkEntry) {
300-
return {
301-
light: lightEntry,
302-
dark: darkEntry,
303-
};
304-
}
263+
return this.getLogoResource(entry);
305264
}
306265
}
307266

@@ -320,9 +279,66 @@ export const getFavicon = (brand: Brand): string | undefined => {
320279
if (!logoInfo) {
321280
return undefined;
322281
}
323-
return logoInfo.light.path;
282+
return logoInfo.path;
324283
};
325284

285+
export async function normalizeLogoSpec(
286+
brand: LightDarkBrand | undefined,
287+
spec: LogoLightDarkSpecifier,
288+
): Promise<NormalizedLogoLightDarkSpecifier> {
289+
const resolveLogo = (mode: "light" | "dark", name: string) => {
290+
const logo = brand?.[mode]?.processedData?.logo;
291+
return logo &&
292+
((Zod.BrandNamedLogo.options.includes(name as BrandNamedLogo) &&
293+
logo[name as BrandNamedLogo]) || logo.images[name]);
294+
};
295+
const resolveLogoOptions = (
296+
mode: "light" | "dark",
297+
logo: LogoOptions,
298+
): LogoOptions => {
299+
const logo2 = resolveLogo(mode, logo.path);
300+
if (logo2) {
301+
const { path: _, ...rest } = logo;
302+
return {
303+
...logo2,
304+
...rest,
305+
};
306+
}
307+
return logo;
308+
};
309+
if (typeof spec === "string") {
310+
return {
311+
light: resolveLogo("light", spec) || { path: spec },
312+
dark: resolveLogo("light", spec) || { path: spec },
313+
};
314+
}
315+
if ("path" in spec) {
316+
return {
317+
light: resolveLogoOptions("light", spec),
318+
dark: resolveLogoOptions("dark", spec),
319+
};
320+
}
321+
let light, dark;
322+
if (spec.light) {
323+
if (typeof spec.light === "string") {
324+
light = resolveLogo("light", spec.light) || { path: spec.light };
325+
} else {
326+
light = resolveLogoOptions("light", spec.light);
327+
}
328+
}
329+
if (spec.dark) {
330+
if (typeof spec.dark === "string") {
331+
dark = resolveLogo("dark", spec.dark) || { path: spec.dark };
332+
} else {
333+
dark = resolveLogoOptions("dark", spec.dark);
334+
}
335+
}
336+
return {
337+
light,
338+
dark,
339+
};
340+
}
341+
326342
function splitColorLightDark(
327343
bcld: BrandColorLightDark,
328344
): LightDarkColor {
@@ -331,42 +347,55 @@ function splitColorLightDark(
331347
}
332348
return bcld;
333349
}
334-
function colorIsUnified(blcd: BrandColorLightDark) {
335-
return typeof blcd === "object" && "dark" in blcd;
336-
}
337-
export function brandIsUnified(brand: BrandUnified): boolean {
350+
351+
const enablesDarkMode = (x: BrandColorLightDark | BrandStringLightDark) =>
352+
typeof x === "object" && x?.dark;
353+
354+
export function brandHasDarkMode(brand: BrandUnified): boolean {
338355
if (brand.color) {
339356
for (const colorName of Zod.BrandNamedThemeColor.options) {
340357
if (!brand.color[colorName]) {
341358
continue;
342359
}
343-
if (colorIsUnified(brand.color![colorName])) {
360+
if (enablesDarkMode(brand.color![colorName])) {
344361
return true;
345362
}
346363
}
347364
}
348365
if (brand.typography) {
349366
for (const elementName of Zod.BrandNamedTypographyElements.options) {
350-
const element = brand.typography![elementName];
367+
const element = brand.typography[elementName];
351368
if (!element || typeof element === "string") {
352369
continue;
353370
}
354371
if (
355372
"background-color" in element && element["background-color"] &&
356-
colorIsUnified(element["background-color"])
373+
enablesDarkMode(element["background-color"])
357374
) {
358375
return true;
359376
}
360377
if (
361378
"color" in element && element["color"] &&
362-
colorIsUnified(element["color"])
379+
enablesDarkMode(element["color"])
363380
) {
364381
return true;
365382
}
366383
}
367384
}
385+
if (brand.logo) {
386+
for (const logoName of Zod.BrandNamedLogo.options) {
387+
const logo = brand.logo[logoName];
388+
if (!logo || typeof logo === "string") {
389+
continue;
390+
}
391+
if (enablesDarkMode(logo)) {
392+
return true;
393+
}
394+
}
395+
}
368396
return false;
369397
}
398+
370399
function sharedTypography(
371400
unified: BrandTypographyUnified,
372401
): BrandTypographySingle {
@@ -389,6 +418,25 @@ function sharedTypography(
389418
}
390419
return ret;
391420
}
421+
422+
function splitLogo(
423+
unifiedLogo: BrandLogoUnified,
424+
): { light: BrandLogoSingle; dark: BrandLogoSingle } {
425+
const light: BrandLogoSingle = { images: unifiedLogo.images },
426+
dark: BrandLogoSingle = { images: unifiedLogo.images };
427+
for (const logoName of Zod.BrandNamedLogo.options) {
428+
if (unifiedLogo[logoName]) {
429+
if (typeof unifiedLogo[logoName] === "string") {
430+
light[logoName] = dark[logoName] = unifiedLogo[logoName];
431+
continue;
432+
}
433+
({ light: light[logoName], dark: dark[logoName] } =
434+
unifiedLogo[logoName]);
435+
}
436+
}
437+
return { light, dark };
438+
}
439+
392440
export function splitUnifiedBrand(
393441
unified: unknown,
394442
brandDir: string,
@@ -528,18 +576,19 @@ export function splitUnifiedBrand(
528576
linkBackgroundColor[mode],
529577
},
530578
};
579+
const logos = unifiedBrand.logo && splitLogo(unifiedBrand.logo);
531580
const lightBrand: BrandSingle = {
532581
meta: unifiedBrand.meta,
533582
color: { palette: unifiedBrand.color && { ...unifiedBrand.color.palette } },
534583
typography: typography && specializeTypography(typography, "light"),
535-
logo: unifiedBrand.logo,
584+
logo: logos && logos.light,
536585
defaults: unifiedBrand.defaults,
537586
};
538587
const darkBrand: BrandSingle = {
539588
meta: unifiedBrand.meta,
540589
color: { palette: unifiedBrand.color && { ...unifiedBrand.color.palette } },
541590
typography: typography && specializeTypography(typography, "dark"),
542-
logo: unifiedBrand.logo,
591+
logo: logos && logos.dark,
543592
defaults: unifiedBrand.defaults,
544593
};
545594
if (unifiedBrand.color) {
@@ -555,7 +604,7 @@ export function splitUnifiedBrand(
555604
}
556605
return {
557606
light: new Brand(lightBrand, brandDir, projectDir),
558-
dark: brandIsUnified(unifiedBrand)
607+
dark: brandHasDarkMode(unifiedBrand)
559608
? new Brand(darkBrand, brandDir, projectDir)
560609
: undefined,
561610
};

src/format/reveal/format-reveal.ts

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import {
2525
Metadata,
2626
PandocFlags,
2727
} from "../../config/types.ts";
28+
import { BrandNamedLogo, Zod } from "../../resources/types/zod/schema-types.ts";
29+
2830
import { mergeConfigs } from "../../core/config.ts";
2931
import { formatResourcePath } from "../../core/resources.ts";
3032
import { renderEjs } from "../../core/ejs.ts";
@@ -377,18 +379,14 @@ export function revealjsFormat() {
377379
const determineRevealLogo = (format: Format): string | undefined => {
378380
const brandData = format.render.brand?.light?.processedData;
379381
if (brandData?.logo) {
380-
const keys: ("medium" | "small" | "large")[] = ["medium", "small", "large"];
381382
// add slide logo if we have one
382-
for (const size of keys) {
383+
for (const size of Zod.BrandNamedLogo.options) {
383384
const logoInfo = brandData.logo[size];
384385
if (!logoInfo) {
385386
continue;
386387
}
387-
if (typeof logoInfo === "string") {
388-
return logoInfo;
389-
} else {
390-
// what to do about light vs dark?
391-
return logoInfo?.light.path ?? logoInfo?.dark.path;
388+
if (logoInfo) {
389+
return logoInfo.path;
392390
}
393391
}
394392
}
@@ -403,14 +401,12 @@ function revealMarkdownAfterBody(format: Format) {
403401
if (typeof revealLogo === "object") {
404402
revealLogo = revealLogo.path;
405403
}
406-
if (["small", "medium", "large"].includes(revealLogo)) {
404+
if (Zod.BrandNamedLogo.options.includes(revealLogo as BrandNamedLogo)) {
407405
const brandData = format.render.brand?.light?.processedData;
408406
const logoInfo = brandData?.logo
409-
?.[revealLogo as ("medium" | "small" | "large")];
410-
if (typeof logoInfo === "string") {
411-
revealLogo = logoInfo;
412-
} else {
413-
revealLogo = logoInfo?.light.path ?? logoInfo?.dark.path;
407+
?.[revealLogo as BrandNamedLogo];
408+
if (logoInfo) {
409+
revealLogo = logoInfo.path;
414410
}
415411
}
416412
} else {

src/project/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { ExecutionEngine, ExecutionTarget } from "../execute/types.ts";
1414
import { InspectedMdCell } from "../inspect/inspect-types.ts";
1515
import { NotebookContext } from "../render/notebook/notebook-types.ts";
1616
import {
17+
LogoLightDarkSpecifier,
1718
NavigationItem as NavItem,
1819
NavigationItemObject,
1920
NavigationItemObject as SidebarTool,
@@ -151,7 +152,7 @@ export const kSidebarMenus = "sidebar-menus";
151152

152153
export interface Navbar {
153154
title?: string | false;
154-
logo?: string;
155+
logo?: LogoLightDarkSpecifier;
155156
[kLogoAlt]?: string;
156157
[kLogoHref]?: string;
157158
background:
@@ -197,7 +198,7 @@ export interface Sidebar {
197198
id?: string;
198199
title?: string;
199200
subtitle?: string;
200-
logo?: string;
201+
logo?: LogoLightDarkSpecifier;
201202
[kLogoAlt]?: string;
202203
[kLogoHref]?: string;
203204
alignment?: "left" | "right" | "center";

0 commit comments

Comments
 (0)