@@ -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" ;
2229import { InternalError } from "../lib/error.ts" ;
2330
2431import { join , relative } from "../../deno_ral/path.ts" ;
2532import { warnOnce } from "../log.ts" ;
2633import { 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
5736type 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+
326342function 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+
370399function 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+
392440export 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 } ;
0 commit comments